nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: elixir-ecto/ecto_sql
Pull request #538 (2023-07-19 15:39:55)

Fix for casting boolean values in MySQL
I'm not sure if this fix is sufficient enough. I've tried it locally and it solves my problem. 


One thing I'm not sure is covered is, what if you pass a value that's not true or false to the cast expression? I assume that's just invalid SQL?

m1dnight: ```sql
select if("true", TRUE, FALSE); -- false
select if("false", TRUE, FALSE);-- false
select if(False, TRUE, FALSE);-- false
select if(TruE, TRUE, FALSE);-- true
select if(TRUE, TRUE, FALSE);-- true
select if(true, TRUE, FALSE);-- true
select if(0, TRUE, FALSE);-- false
select if(1, TRUE, FALSE);-- true
```
As far as I understand, there is not really a  boolean type in MySQL, much like in C. So anything is false unless it's `1` or `true`, or `TRUE`.


Patch:
diff --git a/lib/ecto/adapters/myxql/connection.ex b/lib/ecto/adapters/myxql/connection.ex
index 6e6224f..6cf3b0f 100644
--- a/lib/ecto/adapters/myxql/connection.ex
+++ b/lib/ecto/adapters/myxql/connection.ex
@@ -689,6 +689,10 @@ if Code.ensure_loaded?(MyXQL) do
       [expr(other, sources, query), " + 0"]
     end
 
+    defp expr(%Ecto.Query.Tagged{value: other, type: :boolean}, sources, query) do
+      ["IF(", expr(other, sources, query), ", TRUE, FALSE)"]
+    end
+
     defp expr(%Ecto.Query.Tagged{value: other, type: type}, sources, query) do
       ["CAST(", expr(other, sources, query), " AS ", ecto_cast_to_db(type, query), ?)]
     end


Test patch:
diff --git a/test/ecto/adapters/myxql_test.exs b/test/ecto/adapters/myxql_test.exs
index 0020d2b..33fc927 100644
--- a/test/ecto/adapters/myxql_test.exs
+++ b/test/ecto/adapters/myxql_test.exs
@@ -612,6 +612,16 @@ defmodule Ecto.Adapters.MyXQLTest do
     assert all(query) == ~s{SELECT CAST(? AS char) FROM `schema` AS s0}
   end
 
+  test "boolean type true is cast with an if" do
+    query = Schema |> select([], type(^true, :boolean)) |> plan()
+    assert all(query) == ~s{SELECT IF(?, TRUE, FALSE) FROM `schema` AS s0}
+  end
+
+  test "boolean type false is cast with an if" do
+    query = Schema |> select([], type(^false, :boolean)) |> plan()
+    assert all(query) == ~s{SELECT IF(?, TRUE, FALSE) FROM `schema` AS s0}
+  end
+
   test "json_extract_path" do
     query = Schema |> select([s], json_extract_path(s.meta, [0, 1])) |> plan()
     assert all(query) == ~s{SELECT json_extract(s0.`meta`, '$[0][1]') FROM `schema` AS s0}
Repository: elixir-ecto/ecto_sql
Pull request #545 (2023-07-30 03:01:27)

Don't add comment to removed columns
Closes https://github.com/elixir-ecto/ecto_sql/issues/544

edit: 

Some things I checked:

- It's not an issue for MySQL/TDS. MySQL is handling the case already. TDS doesn't seem like it supports comments.
- `remove_if_exists` doesn't support opts so don't have to worry about it.
- it makes sense to allow the `comment` option for this operation because of the reverse operation


Patch:
diff --git a/lib/ecto/adapters/postgres/connection.ex b/lib/ecto/adapters/postgres/connection.ex
index 61c3237..bf8a68e 100644
--- a/lib/ecto/adapters/postgres/connection.ex
+++ b/lib/ecto/adapters/postgres/connection.ex
@@ -1354,6 +1354,9 @@ if Code.ensure_loaded?(Postgrex) do
 
     defp comments_for_columns(table_name, columns) do
       Enum.flat_map(columns, fn
+        {:remove, _column_name, _column_type, _opts}  ->
+          []
+
         {_operation, column_name, _column_type, opts} ->
           column_name = [table_name, ?. | quote_name(column_name)]
           comments_on("COLUMN", column_name, opts[:comment])


Test patch:
diff --git a/test/ecto/adapters/postgres_test.exs b/test/ecto/adapters/postgres_test.exs
index 5d0895d..c66bb6a 100644
--- a/test/ecto/adapters/postgres_test.exs
+++ b/test/ecto/adapters/postgres_test.exs
@@ -1580,6 +1580,11 @@ defmodule Ecto.Adapters.PostgresTest do
     ~s|COMMENT ON COLUMN "foo"."posts"."updated_at" IS 'column comment 2'|]
   end
 
+  test "removing a column does not add a comment" do
+    alter = {:alter, table(:posts), [{:remove, :title, :string, [comment: "comment"]}]}
+    assert execute_ddl(alter) == [~s/ALTER TABLE "posts" DROP COLUMN "title"/]
+  end
+
   test "create table with references" do
     create = {:create, table(:posts),
               [{:add, :id, :serial, [primary_key: true]},
Repository: elixir-ecto/ecto_sql
Pull request #578 (2023-11-28 00:54:18)

Add index storage parameters for Postgres
Hi, thanks for Ecto!

This PR adds support for [index storage parameters](https://www.postgresql.org/docs/current/sql-createindex.html#SQL-CREATEINDEX-STORAGE-PARAMETERS) for Postgres.

```elixir
index(:posts, [:permalink], options: "fillfactor=50")
```

It uses `:options` for the `WITH` clause [like TDS](https://github.com/elixir-ecto/ecto_sql/blob/d5153e3317cde7a57bfb2c0f89646f06316e9316/lib/ecto/adapters/tds/connection.ex#L1146-L1150).


Patch:
diff --git a/lib/ecto/adapters/postgres/connection.ex b/lib/ecto/adapters/postgres/connection.ex
index 9a094e2..064623e 100644
--- a/lib/ecto/adapters/postgres/connection.ex
+++ b/lib/ecto/adapters/postgres/connection.ex
@@ -1235,6 +1235,7 @@ if Code.ensure_loaded?(Postgrex) do
           ?),
           if_do(include_fields != [], [" INCLUDE ", ?(, include_fields, ?)]),
           maybe_nulls_distinct,
+          if_do(index.options != nil, [" WITH ", ?(, index.options, ?)]),
           if_do(index.where, [" WHERE ", to_string(index.where)])
         ]
       ]


Test patch:
diff --git a/test/ecto/adapters/postgres_test.exs b/test/ecto/adapters/postgres_test.exs
index 0bd7623..f03bee2 100644
--- a/test/ecto/adapters/postgres_test.exs
+++ b/test/ecto/adapters/postgres_test.exs
@@ -2694,6 +2694,13 @@ defmodule Ecto.Adapters.PostgresTest do
              [~s|CREATE INDEX "posts_permalink_index" ON ONLY "posts" ("permalink")|]
   end
 
+  test "create an index with storage parameters" do
+    create = {:create, index(:posts, [:title], options: "fillfactor=50")}
+
+    assert execute_ddl(create) ==
+             [~s|CREATE INDEX "posts_title_index" ON "posts" ("title") WITH (fillfactor=50)|]
+  end
+
   test "drop index" do
     drop = {:drop, index(:posts, [:id], name: "posts$main"), :restrict}
     assert execute_ddl(drop) == [~s|DROP INDEX "posts$main"|]
Repository: elixir-ecto/ecto_sql
Pull request #653 (2025-01-23 15:00:39)

Add prefix support to renaming indices
Why:
* When using [triplex](https://github.com/ateliware/triplex) or similar
  for multi-tenancy with query prefixes, renaming _tables_ within a
  tenant is supported, but renaming an index was not. For example:

  `rename table(:foo), to: table(:bar)` works
  `rename index(:tablename, [:columns], name: "old_index_name"), to: "new_index_name"` fails

This change addresses the need by:
* Making indices similarly prefix-aware as tables.

Not addressed:
* The type of the value to the `:to` option for `rename/2` varies. When
renaming a table, `:to` expects a `%Table{}`, when renaming an index, a string
is expected.



Patch:
diff --git a/lib/ecto/migration.ex b/lib/ecto/migration.ex
index 8b0d819..8073bd1 100644
--- a/lib/ecto/migration.ex
+++ b/lib/ecto/migration.ex
@@ -1195,7 +1195,7 @@ defmodule Ecto.Migration do
   end
 
   def rename(%Index{} = current_index, to: new_name) do
-    Runner.execute({:rename, current_index, new_name})
+    Runner.execute({:rename, __prefix__(current_index), new_name})
     %{current_index | name: new_name}
   end
 


Test patch:
diff --git a/test/ecto/migration_test.exs b/test/ecto/migration_test.exs
index 4b0ede8..fb251ee 100644
--- a/test/ecto/migration_test.exs
+++ b/test/ecto/migration_test.exs
@@ -821,6 +821,23 @@ defmodule Ecto.MigrationTest do
       assert index.prefix == "baz"
     end
 
+    test "renames an index" do
+      rename index(:people, [:name]), to: "person_names_idx"
+      flush()
+      {_, index, new_name} = last_command()
+      assert new_name == "person_names_idx"
+      assert is_nil(index.prefix)
+    end
+
+    @tag prefix: "foo"
+    test "renames an index with a prefix" do
+      rename index(:people, [:name]), to: "person_names_idx"
+      flush()
+      {_, index, new_name} = last_command()
+      assert new_name == "person_names_idx"
+      assert index.prefix == "foo"
+    end
+
     test "executes a command" do
       execute "SELECT 1", "SELECT 2"
       flush()
@@ -1004,6 +1021,23 @@ defmodule Ecto.MigrationTest do
       assert {:create, %Index{}} = last_command()
     end
 
+    test "renames an index" do
+      rename index(:people, [:name]), to: "person_names_idx"
+      flush()
+      {_, index, old_name} = last_command()
+      assert old_name == :people_name_index
+      assert is_nil(index.prefix)
+    end
+
+    @tag prefix: "foo"
+    test "renames an index with a prefix" do
+      rename index(:people, [:name]), to: "person_names_idx"
+      flush()
+      {_, index, old_name} = last_command()
+      assert old_name == :people_name_index
+      assert index.prefix == "foo"
+    end
+
     test "drops a constraint" do
       assert_raise Ecto.MigrationError, ~r/cannot reverse migration command/, fn ->
         drop_if_exists constraint(:posts, :price)
Repository: elixir-ecto/ecto_sql
Pull request #661 (2025-04-22 10:50:30)

Correctly handle generated array columns
Currently, 
```elixir
alter table(:my_table) do
  add :generated_array, {:array, :text}, generated: "always as (existing_array::text[]) stored"
end
```
produces
```sql
ALTER TABLE "my_table" ADD COLUMN "generated_array" text GENERATED always as (existing_array::text[]) stored[]
```
with the `[]` after the GENERATED statement instead of being part of the type definition.

I’m making the assumption that `column_type/2` always returns a two element list (all tests currently pass)

greg-rychlewski: Thank you! Nice catch

Patch:
diff --git a/lib/ecto/adapters/postgres/connection.ex b/lib/ecto/adapters/postgres/connection.ex
index bb045a5..f023bfb 100644
--- a/lib/ecto/adapters/postgres/connection.ex
+++ b/lib/ecto/adapters/postgres/connection.ex
@@ -1750,8 +1750,10 @@ if Code.ensure_loaded?(Postgrex) do
     defp options_expr(options),
       do: [?\s, options]
 
-    defp column_type({:array, type}, opts),
-      do: [column_type(type, opts), "[]"]
+    defp column_type({:array, type}, opts) do
+      [type, opts] = column_type(type, opts)
+      [type, "[]", opts]
+    end
 
     defp column_type(type, opts) when type in ~w(time utc_datetime naive_datetime)a do
       generated = Keyword.get(opts, :generated)


Test patch:
diff --git a/test/ecto/adapters/postgres_test.exs b/test/ecto/adapters/postgres_test.exs
index 0263342..b88d35f 100644
--- a/test/ecto/adapters/postgres_test.exs
+++ b/test/ecto/adapters/postgres_test.exs
@@ -2331,12 +2331,13 @@ defmodule Ecto.Adapters.PostgresTest do
             primary_key: true,
             generated: "ALWAYS AS IDENTITY (MINVALUE  0 START WITH 0 INCREMENT BY 1)"
           ]},
-         {:add, :id_str, :string, [generated: ~s|ALWAYS AS (id) STORED|]}
+         {:add, :id_str, :string, [generated: ~s|ALWAYS AS (id) STORED|]},
+         {:add, :tags, {:array, :text}, [generated: ~s|ALWAYS AS (ARRAY['foo','bar']) STORED|]}
        ]}
 
     assert execute_ddl(create) == [
              """
-             CREATE TABLE "posts" ("id" integer GENERATED ALWAYS AS IDENTITY (MINVALUE  0 START WITH 0 INCREMENT BY 1), "id_str" varchar(255) GENERATED ALWAYS AS (id) STORED, PRIMARY KEY ("id"))
+             CREATE TABLE "posts" ("id" integer GENERATED ALWAYS AS IDENTITY (MINVALUE  0 START WITH 0 INCREMENT BY 1), "id_str" varchar(255) GENERATED ALWAYS AS (id) STORED, \"tags\" text[] GENERATED ALWAYS AS (ARRAY['foo','bar']) STORED, PRIMARY KEY ("id"))
              """
              |> remove_newlines
            ]
Repository: elixir-ecto/ecto_sql
Pull request #676 (2025-06-20 12:29:01)

fix nested array generated columns
Closes https://github.com/elixir-ecto/ecto_sql/issues/675


Patch:
diff --git a/lib/ecto/adapters/postgres/connection.ex b/lib/ecto/adapters/postgres/connection.ex
index 746257e..0f33ab8 100644
--- a/lib/ecto/adapters/postgres/connection.ex
+++ b/lib/ecto/adapters/postgres/connection.ex
@@ -1762,7 +1762,7 @@ if Code.ensure_loaded?(Postgrex) do
 
     defp column_type({:array, type}, opts) do
       [type, opts] = column_type(type, opts)
-      [type, "[]", opts]
+      [[type, "[]"], opts]
     end
 
     defp column_type(type, opts) when type in ~w(time utc_datetime naive_datetime)a do


Test patch:
diff --git a/test/ecto/adapters/postgres_test.exs b/test/ecto/adapters/postgres_test.exs
index b88d35f..6f59ac5 100644
--- a/test/ecto/adapters/postgres_test.exs
+++ b/test/ecto/adapters/postgres_test.exs
@@ -2331,13 +2331,41 @@ defmodule Ecto.Adapters.PostgresTest do
             primary_key: true,
             generated: "ALWAYS AS IDENTITY (MINVALUE  0 START WITH 0 INCREMENT BY 1)"
           ]},
-         {:add, :id_str, :string, [generated: ~s|ALWAYS AS (id) STORED|]},
-         {:add, :tags, {:array, :text}, [generated: ~s|ALWAYS AS (ARRAY['foo','bar']) STORED|]}
+         {:add, :id_str, :string, [generated: ~s|ALWAYS AS (id) STORED|]}
        ]}
 
     assert execute_ddl(create) == [
              """
-             CREATE TABLE "posts" ("id" integer GENERATED ALWAYS AS IDENTITY (MINVALUE  0 START WITH 0 INCREMENT BY 1), "id_str" varchar(255) GENERATED ALWAYS AS (id) STORED, \"tags\" text[] GENERATED ALWAYS AS (ARRAY['foo','bar']) STORED, PRIMARY KEY ("id"))
+             CREATE TABLE "posts" ("id" integer GENERATED ALWAYS AS IDENTITY (MINVALUE  0 START WITH 0 INCREMENT BY 1), "id_str" varchar(255) GENERATED ALWAYS AS (id) STORED, PRIMARY KEY ("id"))
+             """
+             |> remove_newlines
+           ]
+  end
+
+  test "create table with generated array column" do
+    create =
+      {:create, table(:posts),
+       [{:add, :tags, {:array, :text}, [generated: ~s|ALWAYS AS (ARRAY['foo','bar']) STORED|]}]}
+
+    assert execute_ddl(create) == [
+             """
+             CREATE TABLE "posts" ("tags" text[] GENERATED ALWAYS AS (ARRAY['foo','bar']) STORED)
+             """
+             |> remove_newlines
+           ]
+  end
+
+  test "create table with generated nested array column" do
+    create =
+      {:create, table(:posts),
+       [
+         {:add, :tags, {:array, {:array, :text}},
+          [generated: ~s|ALWAYS AS (ARRAY['foo','bar']) STORED|]}
+       ]}
+
+    assert execute_ddl(create) == [
+             """
+             CREATE TABLE "posts" ("tags" text[][] GENERATED ALWAYS AS (ARRAY['foo','bar']) STORED)
              """
              |> remove_newlines
            ]