-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
All - Ecto.Adapters.SQL.Connection #40
Comments
@Danwhy I just got the following error when trying to run a rollback command on the module where I have been testing this dummy adapter... ** (Postgrex.Error) ERROR 42703 (undefined_column) column s0.comment_id_no does not exist
query: SELECT DISTINCT ON (s0."comment_id_no") s0."version"::bigint FROM "schema_migrations" AS s0 FOR UPDATE
(ecto_sql) lib/ecto/adapters/sql.ex:624: Ecto.Adapters.SQL.raise_sql_call_error/1
(ecto_sql) lib/ecto/adapters/sql.ex:557: Ecto.Adapters.SQL.execute/5
(ecto) lib/ecto/repo/queryable.ex:147: Ecto.Repo.Queryable.execute/4
(ecto) lib/ecto/repo/queryable.ex:18: Ecto.Repo.Queryable.all/3
(ecto_sql) lib/ecto/migrator.ex:316: anonymous fn/3 in Ecto.Migrator.lock_for_migrations/3
(ecto_sql) lib/ecto/adapters/sql.ex:820: anonymous fn/3 in Ecto.Adapters.SQL.checkout_or_transaction/4
(db_connection) lib/db_connection.ex:1355: DBConnection.run_transaction/4
(ecto_sql) lib/ecto/adapters/sql.ex:727: Ecto.Adapters.SQL.lock_for_migrations/5
(ecto_sql) lib/ecto/migrator.ex:318: Ecto.Migrator.lock_for_migrations/3
(ecto_sql) lib/mix/tasks/ecto.rollback.ex:106: anonymous fn/4 in Mix.Tasks.Ecto.Rollback.run/2
(elixir) lib/enum.ex:765: Enum."-each/2-lists^foreach/1-0-"/2
(elixir) lib/enum.ex:765: Enum.each/2
(mix) lib/mix/task.ex:316: Mix.Task.run_task/3
(mix) lib/mix/cli.ex:79: Mix.CLI.run_task/2
(elixir) lib/code.ex:767: Code.require_file/2 This is the line that is causing the issue - https://github.com/RobStallion/alog_adapter/blob/master/lib/connection.ex#L36 This appears to be because not all the tables created in the module contain the row "comment_id_no" (equivalent to entry_id). This could be a potential issue in trying to create an ecto adapter. |
@RobStallion Yeah I'd assume that the problem is that the |
I've been having a look into the flow of how the Repo.all query is called: Repo.all -> Ecto.Repo.Queryable.all -> Ecto.Repo.Queryable.execute -> Ecto.Query.Planner.query (Ecto.Query.Planner.plan) -> adapter.execute (Ecto.Adapters.SQL.execute) -> adapter.execute! -> sql_call It looks like the |
I've been doing something similar yesterday to see how the The sources looks to be used (but not defined there) in
|
I think by the time it gets to that function, our Adapter |
Describing the trace call for the
This function is defined in Ecto.Repo module on line 237: https://github.com/elixir-ecto/ecto/blob/2d564df57d29ef021f564af36e4b3ab86f902554/lib/ecto/repo.ex#L237-L239
This function prepare the query which will be passed to the
It adds the prefix defined in the options (options are keywords ie a list of tuple [{otp1: true}, {opt2: "test"}, ...] to the query.
The
So I think the then
which calls
Then
Which runs
And we can see that after the query has been normalised the
we can see that I think I manage to see the lifecycle of the Repo.all function. There are other helpers functions that are called but by doing this trace I understood that the query is first "prepared" then checked if it already exists in ets and if not then the Adapter will be called and the correct function will be triggered. Then postgrex will have the responsability to send the query directly to Postgres and to retrieve the result. |
Trying to recreate a similar subquery to the one currently on alog:
where a1 is the query the adapter The
The error is from
Looking if we can reuse this function |
Trying to apply
|
Looking at @SimonLab 's comment, the following line appears to be where the adapter is called... {count, rows} = adapter.execute(adapter_meta, query_meta, prepared, params, opts) This calls the following function in the adapter... def execute(adapter_meta, query_meta, query, params, opts) do
Ecto.Adapters.SQL.execute(adapter_meta, query_meta, query, params, opts)
end This function is defined here. |
The arguments passed to this function are... [
adapter_meta: %{
cache: #Reference<0.3974704928.2992242689.138205>,
opts: [timeout: 15000, pool_size: 10, pool: DBConnection.ConnectionPool],
pid: #PID<0.2848.0>,
sql: AlogAdapter.Connection,
telemetry: {UsingAlogAdapter.Repo, :debug, [],
[:using_alog_adapter, :repo, :query]}
},
opts: [],
params: [],
prepared: {:cache,
#Function<29.104601620/1 in Ecto.Query.Planner.query_with_cache/7>,
{134695,
"SELECT c0.\"id\", c0.\"comment\", c0.\"comment_id_no\", c0.\"show\", c0.\"cid\", c0.\"entry_id\", c0.\"inserted_at\", c0.\"updated_at\" FROM \"comments\" AS c0"}},
query_meta: %{
preloads: [],
select: %{
assocs: [],
from: {:any,
{:source, {"comments", UsingAlogAdapter.Comments}, nil,
[
id: :id,
comment: :string,
comment_id_no: :string,
show: :boolean,
cid: :string,
entry_id: :string,
inserted_at: :naive_datetime,
updated_at: :naive_datetime
]}},
postprocess: {:source, :from},
preprocess: [source: :from],
take: []
},
sources: {{"comments", UsingAlogAdapter.Comments, nil}}
}
] To clarify, the original call was Repo.all(Comments) |
Next stepI am going to pass in a subquery to |
[
adapter_meta: %{
cache: #Reference<0.872129942.2461401090.223629>,
opts: [timeout: 15000, pool_size: 10, pool: DBConnection.ConnectionPool],
pid: #PID<0.329.0>,
sql: AlogAdapter.Connection,
telemetry: {UsingAlogAdapter.Repo, :debug, [],
[:using_alog_adapter, :repo, :query]}
},
opts: [],
params: [],
prepared: {:cache,
#Function<29.104601620/1 in Ecto.Query.Planner.query_with_cache/7>,
{103,
"SELECT DISTINCT ON (c0.\"cid\") c0.\"id\", c0.\"comment\", c0.\"comment_id_no\", c0.\"show\", c0.\"cid\", c0.\"entry_id\", c0.\"inserted_at\", c0.\"updated_at\" FROM \"comments\" AS c0 WHERE (c0.\"comment_id_no\" = '1') ORDER BY c0.\"cid\", c0.\"inserted_at\" DESC"}},
query_meta: %{
preloads: [],
select: %{
assocs: [],
from: {:any,
{:source, {"comments", UsingAlogAdapter.Comments}, nil,
[
id: :id,
comment: :string,
comment_id_no: :string,
show: :boolean,
cid: :string,
entry_id: :string,
inserted_at: :naive_datetime,
updated_at: :naive_datetime
]}},
postprocess: {:source, :from},
preprocess: [source: :from],
take: []
},
sources: {{"comments", UsingAlogAdapter.Comments, nil}}
}
] These are the arguments passed to the adapters sub =
from(c in Comments,
distinct: c.cid,
order_by: [desc: :inserted_at]
)
query = from(c in sub, where: c.comment_id_no == "1")
Repo.all(query) |
At first glance the arguments passed to our adapter look almost identical, with the OBVIOUS exception of the
|
Hopefully this means that if we can somehow update the query that is passed to the adapter, to add subquery to it. Will look into possible approaches for this. |
My latest attempt was to try to reproduce the logic of the
This function returns an improper list of improper list of string. I'm not certain why exactly improper lists are used here but I think this might be for optimisation and to make pattern matching easier. see https://hexdocs.pm/elixir/master/List.html Then I've looked at the private function
So it looks like it create an improper list which is similar to the from part of an Then try to repeat this process for the
|
The code that will enable access to the all query can be found here. At the moment I am unsure if this function is only called when |
Given a query similar to: Regex.named_captures(~r/(\bSELECT\b)\s(?<fields>.*)\sFROM\s(?<table_name>.*)\sas\s(?<table_as>.*)(?<rest_query>.*)/i, query)
|
Part of #38
https://hexdocs.pm/ecto_sql/Ecto.Adapters.SQL.Connection.html#c:all/1
We need to implement this callback so that it returns the latest version of all rows that match the query parameter.
@RobStallion has already done some research on looking into how we can modify the passed in query, which we can then pass on to the
Ecto.Adapters.Postgres.Connection.all
functionRobStallion/alog_adapter#1
https://stackoverflow.com/questions/54690701/is-there-a-way-to-ensure-where-clause-happens-after-distinct
The text was updated successfully, but these errors were encountered: