Skip to content

Commit 8aa8690

Browse files
authored
fix: resolve issue CREATE/DROP Index concurrently (#10634)
Closes: #10626
1 parent b67ae36 commit 8aa8690

File tree

4 files changed

+81
-5
lines changed

4 files changed

+81
-5
lines changed

docs/indices.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ export class Thing {
140140
## Concurrent creation
141141

142142
In order to avoid having to obtain an access exclusive lock when creating and dropping indexes in postgres, you may create them using the CONCURRENTLY modifier.
143+
If you want use the concurrent option, you need set `migrationsTransactionMode: none` between data source options.
143144

144145
Typeorm supports generating SQL with this option if when the concurrent option is specified on the index.
145146

src/driver/postgres/PostgresQueryRunner.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4297,9 +4297,9 @@ export class PostgresQueryRunner
42974297
.map((columnName) => `"${columnName}"`)
42984298
.join(", ")
42994299
return new Query(
4300-
`CREATE ${index.isUnique ? "UNIQUE " : ""}${
4301-
index.isConcurrent ? "CONCURRENTLY " : ""
4302-
}INDEX "${index.name}" ON ${this.escapePath(table)} ${
4300+
`CREATE ${index.isUnique ? "UNIQUE " : ""}INDEX${
4301+
index.isConcurrent ? " CONCURRENTLY" : ""
4302+
} "${index.name}" ON ${this.escapePath(table)} ${
43034303
index.isSpatial ? "USING GiST " : ""
43044304
}(${columns}) ${index.where ? "WHERE " + index.where : ""}`,
43054305
)
@@ -4338,12 +4338,12 @@ export class PostgresQueryRunner
43384338
return schema
43394339
? new Query(
43404340
`DROP INDEX ${
4341-
concurrent ? "CONCURRENTLY" : ""
4341+
concurrent ? "CONCURRENTLY " : ""
43424342
}"${schema}"."${indexName}"`,
43434343
)
43444344
: new Query(
43454345
`DROP INDEX ${
4346-
concurrent ? "CONCURRENTLY" : ""
4346+
concurrent ? "CONCURRENTLY " : ""
43474347
}"${indexName}"`,
43484348
)
43494349
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Column, Entity, Index, PrimaryGeneratedColumn } from "../../../../src"
2+
3+
@Entity({
4+
name: "user",
5+
})
6+
export class User {
7+
@PrimaryGeneratedColumn()
8+
id: number
9+
10+
@Index("concurrentTest", { concurrent: true })
11+
@Column({ nullable: true })
12+
name: string
13+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import "reflect-metadata"
2+
import {
3+
createTestingConnections,
4+
closeTestingConnections,
5+
} from "../../utils/test-utils"
6+
import { DataSource } from "../../../src/index.js"
7+
import { expect } from "chai"
8+
9+
describe("github issues > #10626 Postgres CREATE INDEX CONCURRENTLY bug", () => {
10+
let dataSources: DataSource[]
11+
12+
before(
13+
async () =>
14+
(dataSources = await createTestingConnections({
15+
entities: [__dirname + "/entity/*{.js,.ts}"],
16+
schemaCreate: false,
17+
dropSchema: true,
18+
enabledDrivers: ["postgres"],
19+
logging: true,
20+
})),
21+
)
22+
23+
after(() => closeTestingConnections(dataSources))
24+
25+
it("has to create INDEX CONCURRENTLY", () =>
26+
Promise.all(
27+
dataSources.map(async (dataSource) => {
28+
await dataSource.setOptions({
29+
...dataSource.options,
30+
migrationsTransactionMode: "none",
31+
})
32+
await dataSource.synchronize()
33+
const concurrentTestIndexes = await dataSource.query(
34+
`SELECT * FROM pg_indexes WHERE indexname = 'concurrentTest'`,
35+
)
36+
expect(concurrentTestIndexes).has.length(1)
37+
}),
38+
))
39+
40+
it("has to drop INDEX CONCURRENTLY", () =>
41+
Promise.all(
42+
dataSources.map(async (dataSource) => {
43+
await dataSource.setOptions({
44+
...dataSource.options,
45+
migrationsTransactionMode: "none",
46+
})
47+
await dataSource.synchronize()
48+
49+
const queryRunner = dataSource.createQueryRunner()
50+
let table = await queryRunner.getTable("user")
51+
if (table) {
52+
await queryRunner.dropIndex(table, table?.indices[0])
53+
}
54+
const queries = queryRunner.getMemorySql().upQueries
55+
expect(queries[0].query).to.be.eql(
56+
'DROP INDEX "public"."concurrentTest"',
57+
)
58+
59+
await queryRunner.release()
60+
}),
61+
))
62+
})

0 commit comments

Comments
 (0)