changed CHANGELOG.md
 
@@ -1,5 1,17 @@
1
1
# Changelog for v3.x
2
2
3
## v3.11.1 (2023-12-07)
4
5
### Enhancements
6
7
* [Ecto.Migration] Add `:generated` option to columns
8
* [Ecto.Migration] Add index storage parameters (via :options) for Postgres
9
10
### Bug fixes
11
12
* [Ecto.Migrations] Support `:prefix` on index rename
13
* [Ecto.Migrator] Stop runner if migration fails
14
3
15
## v3.11.0 (2023-11-14)
4
16
5
17
### Enhancements
changed hex_metadata.config
 
@@ -1,10 1,7 @@
1
- {<<"links">>,[{<<"GitHub">>,<<"https://github.com/elixir-ecto/ecto_sql">>}]}.
2
- {<<"name">>,<<"ecto_sql">>}.
3
- {<<"version">>,<<"3.11.0">>}.
1
{<<"app">>,<<"ecto_sql">>}.
2
{<<"build_tools">>,[<<"mix">>]}.
4
3
{<<"description">>,<<"SQL-based adapters for Ecto and database migrations">>}.
5
4
{<<"elixir">>,<<"~> 1.11">>}.
6
- {<<"app">>,<<"ecto_sql">>}.
7
- {<<"licenses">>,[<<"Apache-2.0">>]}.
8
5
{<<"files">>,
9
6
[<<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>,<<"CHANGELOG.md">>,
10
7
<<"lib">>,<<"lib/ecto">>,<<"lib/ecto/adapter">>,
 
@@ -40,35 37,38 @@
40
37
<<"integration_test/support/file_helpers.exs">>,
41
38
<<"integration_test/support/migration.exs">>,
42
39
<<"integration_test/support/repo.exs">>]}.
40
{<<"licenses">>,[<<"Apache-2.0">>]}.
41
{<<"links">>,[{<<"GitHub">>,<<"https://github.com/elixir-ecto/ecto_sql">>}]}.
42
{<<"name">>,<<"ecto_sql">>}.
43
43
{<<"requirements">>,
44
- [[{<<"name">>,<<"ecto">>},
45
- {<<"app">>,<<"ecto">>},
44
[[{<<"app">>,<<"ecto">>},
45
{<<"name">>,<<"ecto">>},
46
46
{<<"optional">>,false},
47
- {<<"requirement">>,<<"~> 3.11.0">>},
48
- {<<"repository">>,<<"hexpm">>}],
49
- [{<<"name">>,<<"telemetry">>},
50
- {<<"app">>,<<"telemetry">>},
47
{<<"repository">>,<<"hexpm">>},
48
{<<"requirement">>,<<"~> 3.11.0">>}],
49
[{<<"app">>,<<"telemetry">>},
50
{<<"name">>,<<"telemetry">>},
51
51
{<<"optional">>,false},
52
- {<<"requirement">>,<<"~> 0.4.0 or ~> 1.0">>},
53
- {<<"repository">>,<<"hexpm">>}],
54
- [{<<"name">>,<<"db_connection">>},
55
- {<<"app">>,<<"db_connection">>},
52
{<<"repository">>,<<"hexpm">>},
53
{<<"requirement">>,<<"~> 0.4.0 or ~> 1.0">>}],
54
[{<<"app">>,<<"db_connection">>},
55
{<<"name">>,<<"db_connection">>},
56
56
{<<"optional">>,false},
57
- {<<"requirement">>,<<"~> 2.5 or ~> 2.4.1">>},
58
- {<<"repository">>,<<"hexpm">>}],
59
- [{<<"name">>,<<"postgrex">>},
60
- {<<"app">>,<<"postgrex">>},
57
{<<"repository">>,<<"hexpm">>},
58
{<<"requirement">>,<<"~> 2.5 or ~> 2.4.1">>}],
59
[{<<"app">>,<<"postgrex">>},
60
{<<"name">>,<<"postgrex">>},
61
61
{<<"optional">>,true},
62
- {<<"requirement">>,<<"~> 0.16.0 or ~> 0.17.0 or ~> 1.0">>},
63
- {<<"repository">>,<<"hexpm">>}],
64
- [{<<"name">>,<<"myxql">>},
65
- {<<"app">>,<<"myxql">>},
62
{<<"repository">>,<<"hexpm">>},
63
{<<"requirement">>,<<"~> 0.16.0 or ~> 0.17.0 or ~> 1.0">>}],
64
[{<<"app">>,<<"myxql">>},
65
{<<"name">>,<<"myxql">>},
66
66
{<<"optional">>,true},
67
- {<<"requirement">>,<<"~> 0.6.0">>},
68
- {<<"repository">>,<<"hexpm">>}],
69
- [{<<"name">>,<<"tds">>},
70
- {<<"app">>,<<"tds">>},
67
{<<"repository">>,<<"hexpm">>},
68
{<<"requirement">>,<<"~> 0.6.0">>}],
69
[{<<"app">>,<<"tds">>},
70
{<<"name">>,<<"tds">>},
71
71
{<<"optional">>,true},
72
- {<<"requirement">>,<<"~> 2.1.1 or ~> 2.2">>},
73
- {<<"repository">>,<<"hexpm">>}]]}.
74
- {<<"build_tools">>,[<<"mix">>]}.
72
{<<"repository">>,<<"hexpm">>},
73
{<<"requirement">>,<<"~> 2.1.1 or ~> 2.2">>}]]}.
74
{<<"version">>,<<"3.11.1">>}.
changed integration_test/sql/migrator.exs
 
@@ -112,6 112,7 @@ defmodule Ecto.Integration.MigratorTest do
112
112
113
113
test "bad execute migration" do
114
114
assert catch_error(up(PoolRepo, 31, BadMigration, log: false))
115
assert DynamicSupervisor.which_children(Ecto.MigratorSupervisor) == []
115
116
end
116
117
117
118
test "broken link migration" do
changed lib/ecto/adapters/myxql/connection.ex
 
@@ -1256,28 1256,46 @@ if Code.ensure_loaded?(MyXQL) do
1256
1256
defp options_expr(options),
1257
1257
do: [?\s, to_string(options)]
1258
1258
1259
- defp column_type(type, _opts) when type in ~w(time utc_datetime naive_datetime)a,
1260
- do: ecto_to_db(type)
1259
defp column_type(type, opts) when type in ~w(time utc_datetime naive_datetime)a do
1260
generated = Keyword.get(opts, :generated)
1261
[ecto_to_db(type), generated_expr(generated)]
1262
end
1261
1263
1262
1264
defp column_type(type, opts)
1263
1265
when type in ~w(time_usec utc_datetime_usec naive_datetime_usec)a do
1264
1266
precision = Keyword.get(opts, :precision, 6)
1267
generated = Keyword.get(opts, :generated)
1265
1268
type_name = ecto_to_db(type)
1266
1269
1267
- [type_name, ?(, to_string(precision), ?)]
1270
[type_name, ?(, to_string(precision), ?), generated_expr(generated)]
1268
1271
end
1269
1272
1270
1273
defp column_type(type, opts) do
1271
1274
size = Keyword.get(opts, :size)
1272
1275
precision = Keyword.get(opts, :precision)
1276
generated = Keyword.get(opts, :generated)
1273
1277
scale = Keyword.get(opts, :scale)
1274
1278
1275
- cond do
1276
- size -> [ecto_size_to_db(type), ?(, to_string(size), ?)]
1277
- precision -> [ecto_to_db(type), ?(, to_string(precision), ?,, to_string(scale || 0), ?)]
1278
- type == :string -> ["varchar(255)"]
1279
- true -> ecto_to_db(type)
1280
- end
1279
type =
1280
cond do
1281
size -> [ecto_size_to_db(type), ?(, to_string(size), ?)]
1282
precision -> [ecto_to_db(type), ?(, to_string(precision), ?,, to_string(scale || 0), ?)]
1283
type == :string -> ["varchar(255)"]
1284
true -> ecto_to_db(type)
1285
end
1286
1287
[type, generated_expr(generated)]
1288
end
1289
1290
defp generated_expr(nil), do: []
1291
1292
defp generated_expr(expr) when is_binary(expr) do
1293
[" AS ", expr]
1294
end
1295
1296
defp generated_expr(other) do
1297
raise ArgumentError,
1298
"the `:generated` option only accepts strings, received: #{inspect(other)}"
1281
1299
end
1282
1300
1283
1301
defp reference_expr(type, ref, table, name) do
changed lib/ecto/adapters/postgres/connection.ex
 
@@ -230,7 230,7 @@ if Code.ensure_loaded?(Postgrex) do
230
230
231
231
[
232
232
"INSERT INTO ",
233
- quote_table(prefix, table),
233
quote_name(prefix, table),
234
234
insert_as(on_conflict),
235
235
values,
236
236
on_conflict(on_conflict, header) | returning(returning)
 
@@ -332,7 332,7 @@ if Code.ensure_loaded?(Postgrex) do
332
332
333
333
[
334
334
"UPDATE ",
335
- quote_table(prefix, table),
335
quote_name(prefix, table),
336
336
" SET ",
337
337
fields,
338
338
" WHERE ",
 
@@ -351,7 351,7 @@ if Code.ensure_loaded?(Postgrex) do
351
351
{[quote_name(field), " = $" | Integer.to_string(acc)], acc 1}
352
352
end)
353
353
354
- ["DELETE FROM ", quote_table(prefix, table), " WHERE ", filters | returning(returning)]
354
["DELETE FROM ", quote_name(prefix, table), " WHERE ", filters | returning(returning)]
355
355
end
356
356
357
357
@impl true
 
@@ -1136,7 1136,7 @@ if Code.ensure_loaded?(Postgrex) do
1136
1136
1137
1137
{table, schema, prefix} ->
1138
1138
name = as_prefix [create_alias(table) | Integer.to_string(pos)]
1139
- {quote_table(prefix, table), name, schema}
1139
{quote_name(prefix, table), name, schema}
1140
1140
1141
1141
�to.SubQuery{} ->
1142
1142
{nil, as_prefix [?s | Integer.to_string(pos)], nil}
 
@@ -1160,7 1160,7 @@ if Code.ensure_loaded?(Postgrex) do
1160
1160
1161
1161
@impl true
1162
1162
def execute_ddl({command, %Table{} = table, columns}) when command in @creates do
1163
- table_name = quote_table(table.prefix, table.name)
1163
table_name = quote_name(table.prefix, table.name)
1164
1164
1165
1165
query = [
1166
1166
"CREATE TABLE ",
 
@@ -1184,14 1184,14 @@ if Code.ensure_loaded?(Postgrex) do
1184
1184
[
1185
1185
"DROP TABLE ",
1186
1186
if_do(command == :drop_if_exists, "IF EXISTS "),
1187
- quote_table(table.prefix, table.name),
1187
quote_name(table.prefix, table.name),
1188
1188
drop_mode(mode)
1189
1189
]
1190
1190
]
1191
1191
end
1192
1192
1193
1193
def execute_ddl({:alter, %Table{} = table, changes}) do
1194
- table_name = quote_table(table.prefix, table.name)
1194
table_name = quote_name(table.prefix, table.name)
1195
1195
1196
1196
query = [
1197
1197
"ALTER TABLE ",
 
@@ -1227,7 1227,7 @@ if Code.ensure_loaded?(Postgrex) do
1227
1227
quote_name(index.name),
1228
1228
" ON ",
1229
1229
if_do(index.only, "ONLY "),
1230
- quote_table(index.prefix, index.table),
1230
quote_name(index.prefix, index.table),
1231
1231
if_do(index.using, [" USING ", to_string(index.using)]),
1232
1232
?\s,
1233
1233
?(,
 
@@ -1235,11 1235,12 @@ if Code.ensure_loaded?(Postgrex) do
1235
1235
?),
1236
1236
if_do(include_fields != [], [" INCLUDE ", ?(, include_fields, ?)]),
1237
1237
maybe_nulls_distinct,
1238
if_do(index.options != nil, [" WITH ", ?(, index.options, ?)]),
1238
1239
if_do(index.where, [" WHERE ", to_string(index.where)])
1239
1240
]
1240
1241
]
1241
1242
1242
- queries comments_on("INDEX", quote_table(index.prefix, index.name), index.comment)
1243
queries comments_on("INDEX", quote_name(index.prefix, index.name), index.comment)
1243
1244
end
1244
1245
1245
1246
def execute_ddl({command, %Index{} = index, mode}) when command in @drops do
 
@@ -1248,23 1249,30 @@ if Code.ensure_loaded?(Postgrex) do
1248
1249
"DROP INDEX ",
1249
1250
if_do(index.concurrently, "CONCURRENTLY "),
1250
1251
if_do(command == :drop_if_exists, "IF EXISTS "),
1251
- quote_table(index.prefix, index.name),
1252
quote_name(index.prefix, index.name),
1252
1253
drop_mode(mode)
1253
1254
]
1254
1255
]
1255
1256
end
1256
1257
1257
1258
def execute_ddl({:rename, %Index{} = current_index, new_name}) do
1258
- [["ALTER INDEX ", quote_name(current_index.name), " RENAME TO ", quote_name(new_name)]]
1259
[
1260
[
1261
"ALTER INDEX ",
1262
quote_name(current_index.prefix, current_index.name),
1263
" RENAME TO ",
1264
quote_name(new_name)
1265
]
1266
]
1259
1267
end
1260
1268
1261
1269
def execute_ddl({:rename, %Table{} = current_table, %Table{} = new_table}) do
1262
1270
[
1263
1271
[
1264
1272
"ALTER TABLE ",
1265
- quote_table(current_table.prefix, current_table.name),
1273
quote_name(current_table.prefix, current_table.name),
1266
1274
" RENAME TO ",
1267
- quote_table(nil, new_table.name)
1275
quote_name(nil, new_table.name)
1268
1276
]
1269
1277
]
1270
1278
end
 
@@ -1273,7 1281,7 @@ if Code.ensure_loaded?(Postgrex) do
1273
1281
[
1274
1282
[
1275
1283
"ALTER TABLE ",
1276
- quote_table(table.prefix, table.name),
1284
quote_name(table.prefix, table.name),
1277
1285
" RENAME ",
1278
1286
quote_name(current_column),
1279
1287
" TO ",
 
@@ -1283,7 1291,7 @@ if Code.ensure_loaded?(Postgrex) do
1283
1291
end
1284
1292
1285
1293
def execute_ddl({:create, %Constraint{} = constraint}) do
1286
- table_name = quote_table(constraint.prefix, constraint.table)
1294
table_name = quote_name(constraint.prefix, constraint.table)
1287
1295
queries = [["ALTER TABLE ", table_name, " ADD ", new_constraint_expr(constraint)]]
1288
1296
1289
1297
queries comments_on("CONSTRAINT", constraint.name, constraint.comment, table_name)
 
@@ -1293,7 1301,7 @@ if Code.ensure_loaded?(Postgrex) do
1293
1301
[
1294
1302
[
1295
1303
"ALTER TABLE ",
1296
- quote_table(constraint.prefix, constraint.table),
1304
quote_name(constraint.prefix, constraint.table),
1297
1305
" DROP CONSTRAINT ",
1298
1306
if_do(command == :drop_if_exists, "IF EXISTS "),
1299
1307
quote_name(constraint.name),
 
@@ -1610,41 1618,52 @@ if Code.ensure_loaded?(Postgrex) do
1610
1618
defp column_type({:array, type}, opts),
1611
1619
do: [column_type(type, opts), "[]"]
1612
1620
1613
- defp column_type(type, _opts) when type in ~w(time utc_datetime naive_datetime)a,
1614
- do: [ecto_to_db(type), "(0)"]
1621
defp column_type(type, opts) when type in ~w(time utc_datetime naive_datetime)a do
1622
generated = Keyword.get(opts, :generated)
1623
[ecto_to_db(type), "(0)", generated_expr(generated)]
1624
end
1615
1625
1616
1626
defp column_type(type, opts)
1617
1627
when type in ~w(time_usec utc_datetime_usec naive_datetime_usec)a do
1618
1628
precision = Keyword.get(opts, :precision)
1629
generated = Keyword.get(opts, :generated)
1619
1630
type_name = ecto_to_db(type)
1620
1631
1621
- if precision do
1622
- [type_name, ?(, to_string(precision), ?)]
1623
- else
1624
- type_name
1625
- end
1632
type =
1633
if precision do
1634
[type_name, ?(, to_string(precision), ?)]
1635
else
1636
type_name
1637
end
1638
1639
[type, generated_expr(generated)]
1626
1640
end
1627
1641
1628
1642
defp column_type(:identity, opts) do
1629
1643
start_value = [Keyword.get(opts, :start_value)]
1630
1644
increment = [Keyword.get(opts, :increment)]
1645
generated = Keyword.get(opts, :generated)
1631
1646
type_name = ecto_to_db(:identity)
1632
1647
1633
- cleanup = fn v -> is_integer(v) and v > 0 end
1648
if generated do
1649
[type_name, generated_expr(generated)]
1650
else
1651
cleanup = fn v -> is_integer(v) and v > 0 end
1634
1652
1635
- sequence =
1636
- start_value
1637
- |> Enum.filter(cleanup)
1638
- |> Enum.map(&"START WITH #{&1}")
1639
- |> Kernel. (
1640
- increment
1653
sequence =
1654
start_value
1641
1655
|> Enum.filter(cleanup)
1642
- |> Enum.map(&"INCREMENT BY #{&1}")
1643
- )
1656
|> Enum.map(&"START WITH #{&1}")
1657
|> Kernel. (
1658
increment
1659
|> Enum.filter(cleanup)
1660
|> Enum.map(&"INCREMENT BY #{&1}")
1661
)
1644
1662
1645
- case sequence do
1646
- [] -> [type_name, " GENERATED BY DEFAULT AS IDENTITY"]
1647
- _ -> [type_name, " GENERATED BY DEFAULT AS IDENTITY(", Enum.join(sequence, " "), ") "]
1663
case sequence do
1664
[] -> [type_name, " GENERATED BY DEFAULT AS IDENTITY"]
1665
_ -> [type_name, " GENERATED BY DEFAULT AS IDENTITY(", Enum.join(sequence, " "), ") "]
1666
end
1648
1667
end
1649
1668
end
1650
1669
 
@@ -1652,14 1671,29 @@ if Code.ensure_loaded?(Postgrex) do
1652
1671
size = Keyword.get(opts, :size)
1653
1672
precision = Keyword.get(opts, :precision)
1654
1673
scale = Keyword.get(opts, :scale)
1674
generated = Keyword.get(opts, :generated)
1655
1675
type_name = ecto_to_db(type)
1656
1676
1657
- cond do
1658
- size -> [type_name, ?(, to_string(size), ?)]
1659
- precision -> [type_name, ?(, to_string(precision), ?,, to_string(scale || 0), ?)]
1660
- type == :string -> [type_name, "(255)"]
1661
- true -> type_name
1662
- end
1677
type =
1678
cond do
1679
size -> [type_name, ?(, to_string(size), ?)]
1680
precision -> [type_name, ?(, to_string(precision), ?,, to_string(scale || 0), ?)]
1681
type == :string -> [type_name, "(255)"]
1682
true -> type_name
1683
end
1684
1685
[type, generated_expr(generated)]
1686
end
1687
1688
defp generated_expr(nil), do: []
1689
1690
defp generated_expr(expr) when is_binary(expr) do
1691
[" GENERATED ", expr]
1692
end
1693
1694
defp generated_expr(other) do
1695
raise ArgumentError,
1696
"the `:generated` option only accepts strings, received: #{inspect(other)}"
1663
1697
end
1664
1698
1665
1699
defp reference_expr(%Reference{} = ref, table, name) do
 
@@ -1672,7 1706,7 @@ if Code.ensure_loaded?(Postgrex) do
1672
1706
"FOREIGN KEY (",
1673
1707
quote_names(current_columns),
1674
1708
") REFERENCES ",
1675
- quote_table(ref.prefix || table.prefix, ref.table),
1709
quote_name(ref.prefix || table.prefix, ref.table),
1676
1710
?(,
1677
1711
quote_names(reference_columns),
1678
1712
?),
 
@@ -1762,27 1796,17 @@ if Code.ensure_loaded?(Postgrex) do
1762
1796
Enum.map_intersperse(names, ?,, &quote_name/1)
1763
1797
end
1764
1798
1799
defp quote_name(nil, name), do: quote_name(name)
1800
1801
defp quote_name(prefix, name), do: [quote_name(prefix), ?., quote_name(name)]
1802
1765
1803
defp quote_name(name) when is_atom(name) do
1766
1804
quote_name(Atom.to_string(name))
1767
1805
end
1768
1806
1769
1807
defp quote_name(name) when is_binary(name) do
1770
1808
if String.contains?(name, "\"") do
1771
- error!(nil, "bad literal/field/table name #{inspect(name)} (\" is not permitted)")
1772
- end
1773
-
1774
- [?", name, ?"]
1775
- end
1776
-
1777
- defp quote_table(nil, name), do: quote_table(name)
1778
- defp quote_table(prefix, name), do: [quote_table(prefix), ?., quote_table(name)]
1779
-
1780
- defp quote_table(name) when is_atom(name),
1781
- do: quote_table(Atom.to_string(name))
1782
-
1783
- defp quote_table(name) do
1784
- if String.contains?(name, "\"") do
1785
- error!(nil, "bad table name #{inspect(name)}")
1809
error!(nil, "bad literal/field/index/table name #{inspect(name)} (\" is not permitted)")
1786
1810
end
1787
1811
1788
1812
[?", name, ?"]
changed lib/ecto/adapters/tds/connection.ex
 
@@ -1544,7 1544,19 @@ if Code.ensure_loaded?(Tds) do
1544
1544
size = Keyword.get(opts, :size)
1545
1545
precision = Keyword.get(opts, :precision)
1546
1546
scale = Keyword.get(opts, :scale)
1547
- ecto_to_db(type, size, precision, scale)
1547
generated = Keyword.get(opts, :generated)
1548
[ecto_to_db(type, size, precision, scale), generated_expr(generated)]
1549
end
1550
1551
defp generated_expr(nil), do: []
1552
1553
defp generated_expr(expr) when is_binary(expr) do
1554
[" AS ", expr]
1555
end
1556
1557
defp generated_expr(other) do
1558
raise ArgumentError,
1559
"the `:generated` option only accepts strings, received: #{inspect(other)}"
1548
1560
end
1549
1561
1550
1562
defp constraint_expr(%Reference{} = ref, table, name) do
changed lib/ecto/migration.ex
 
@@ -771,25 771,29 @@ defmodule Ecto.Migration do
771
771
## Options
772
772
773
773
* `:name` - the name of the index. Defaults to "#{table}_#{column}_index".
774
- * `:unique` - indicates whether the index should be unique. Defaults to
775
- `false`.
776
- * `:concurrently` - indicates whether the index should be created/dropped
777
- concurrently.
778
- * `:using` - configures the index type.
779
774
* `:prefix` - specify an optional prefix for the index.
780
- * `:where` - specify conditions for a partial index.
781
- * `:include` - specify fields for a covering index. This is not supported
782
- by all databases. For more information on PostgreSQL support, please
783
- [read the official docs](https://www.postgresql.org/docs/current/indexes-index-only-scans.html).
775
* `:unique` - indicates whether the index should be unique. Defaults to `false`.
776
* `:comment` - adds a comment to the index.
777
* `:using` - configures the index type.
778
779
Some options are supported only by some databases:
780
781
* `:concurrently` - indicates whether the index should be created/dropped
782
concurrently in MSSQL and PostgreSQL.
783
* `:include` - specify fields for a covering index,
784
[supported by PostgreSQL only](https://www.postgresql.org/docs/current/indexes-index-only-scans.html).
784
785
* `:nulls_distinct` - specify whether null values should be considered
785
786
distinct for a unique index. Defaults to `nil`, which will not add the
786
787
parameter to the generated SQL and thus use the database default.
787
788
This option is currently only supported by PostgreSQL 15 .
788
789
For MySQL, it is always false. For MSSQL, it is always true.
789
790
See the dedicated section on this option for more information.
790
- * `:only` - Indicates not to recurse creating indexes on partitions, if the table is partitioned.
791
- This option is currently only supported by PostgreSQL 11 . Defaults to `false`.
792
- * `:comment` - adds a comment to the index.
791
* `:only` - indicates to not recurse creating indexes on partitions.
792
[supported by PostgreSQL only](https://www.postgresql.org/docs/current/ddl-partitioning.html#DDL-PARTITIONING-DECLARATIVE-MAINTENANCE).
793
* `:options` - configures index options (WITH clause) for both PostgreSQL
794
and MSSQL
795
* `:where` - specify conditions for a partial index (PostgreSQL) /
796
filtered index (MSSQL).
793
797
794
798
## Adding/dropping indexes concurrently
795
799
 
@@ -1088,6 1092,9 @@ defmodule Ecto.Migration do
1088
1092
add :summary, :text # Database type
1089
1093
add :object, :map # Elixir type which is handled by the database
1090
1094
add :custom, :'"UserDefinedType"' # A case-sensitive, user-defined type name
1095
add :identity, :integer, generated: "BY DEFAULT AS IDENTITY" # Postgres generated identity column
1096
add :generated_psql, :string, generated: "ALWAYS AS (id::text) STORED" # Postgres calculated column
1097
add :generated_other, :string, generated: "CAST(id AS char)" # MySQL and TDS calculated column
1091
1098
end
1092
1099
1093
1100
## Options
 
@@ -1108,6 1115,9 @@ defmodule Ecto.Migration do
1108
1115
* `:comment` - adds a comment to the added column.
1109
1116
* `:after` - positions field after the specified one. Only supported on MySQL,
1110
1117
it is ignored by other databases.
1118
* `:generated` - a string representing the expression for a generated column. See
1119
above for a comprehensive set of examples for each of the built-in adapters. If
1120
specified alongside `:start_value`/`:increment`, those options will be ignored.
1111
1121
* `:start_value` - option for `:identity` key, represents initial value in sequence
1112
1122
generation. Default is defined by the database.
1113
1123
* `:increment` - option for `:identity` key, represents increment value for
changed lib/ecto/migration/runner.ex
 
@@ -24,7 24,7 @@ defmodule Ecto.Migration.Runner do
24
24
log(level, "== Running #{version} #{inspect(module)}.#{operation}/0 #{direction}")
25
25
{time, _} = :timer.tc(fn -> perform_operation(repo, module, operation) end)
26
26
log(level, "== Migrated #{version} in #{inspect(div(time, 100_000) / 10)}s")
27
-
27
after
28
28
stop()
29
29
end
30
30
 
@@ -460,7 460,7 @@ defmodule Ecto.Migration.Runner do
460
460
do: "drop index if exists #{quote_name(index.prefix, index.name)}#{drop_mode(mode)}"
461
461
462
462
defp command({:rename, %Index{} = index_current, new_name}),
463
- do: "rename index #{quote_name(index_current.name)} to #{new_name}"
463
do: "rename index #{quote_name(index_current.prefix, index_current.name)} to #{new_name}"
464
464
465
465
defp command({:rename, %Table{} = current_table, %Table{} = new_table}),
466
466
do:
changed mix.exs
 
@@ -2,7 2,7 @@ defmodule EctoSQL.MixProject do
2
2
use Mix.Project
3
3
4
4
@source_url "https://github.com/elixir-ecto/ecto_sql"
5
- @version "3.11.0"
5
@version "3.11.1"
6
6
@adapters ~w(pg myxql tds)
7
7
8
8
def project do
 
@@ -68,8 68,7 @@ defmodule EctoSQL.MixProject do
68
68
{:ex_doc, "~> 0.21", only: :docs},
69
69
70
70
# Benchmarks
71
- {:benchee, "~> 0.11.0", only: :bench},
72
- {:benchee_json, "~> 0.4.0", only: :bench}
71
{:benchee, "~> 1.0", only: :bench}
73
72
]
74
73
end