+
Skip to content

Support for PostgreSQL SKIP LOCKED #238

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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ Pull requests are always welcome and can be a quick way to get your fix or impro

- By contributing to Ktorm, you agree to uphold our [Code of Conduct](CODE_OF_CONDUCT.md).
- By contributing to Ktorm, you agree that your contributions will be licensed under [Apache License 2.0](LICENSE).
- Coding Conventions are very import. Refer to the [Kotlin Style Guide](https://kotlinlang.org/docs/reference/coding-conventions.html) for the recommended coding standards of Ktorm.
- Coding Conventions are very important. Refer to the [Kotlin Style Guide](https://kotlinlang.org/docs/reference/coding-conventions.html) for the recommended coding standards of Ktorm.
- If you've added code that should be tested, add tests and ensure they all pass. If you've changed APIs, update the documentation.
- If it's your first time contributing to Ktorm, please also update the `build.gradle` file, add your GitHub ID to the developers info, which will let more people know your contributions.
7 changes: 6 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
buildscript {
ext {
kotlinVersion = "1.4.21"
detektVersion = "1.12.0-RC1"
detektVersion = "1.14.2"
}
repositories {
jcenter()
Expand Down Expand Up @@ -162,6 +162,11 @@ subprojects { project ->
name = "Pedro Domingues"
email = "pedro.domingues.pt@gmail.com"
}
developer {
id = "sigmanil"
name = "Sigmund M. Nilssen"
email = "sigmundn@gmail.com"
}
}
scm {
url = "https://github.com/kotlin-orm/ktorm.git"
Expand Down
2 changes: 1 addition & 1 deletion ktorm-support-mysql/ktorm-support-mysql.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ dependencies {
testImplementation project(path: ":ktorm-core", configuration: "testOutput")
testImplementation project(":ktorm-jackson")
testImplementation "mysql:mysql-connector-java:8.0.13"
testImplementation "org.testcontainers:mysql:1.11.3"
testImplementation "org.testcontainers:mysql:1.15.1"
}
2 changes: 1 addition & 1 deletion ktorm-support-oracle/ktorm-support-oracle.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ dependencies {

testImplementation project(path: ":ktorm-core", configuration: "testOutput")
testImplementation fileTree(dir: "lib", includes: ["*.jar"])
testImplementation "org.testcontainers:oracle-xe:1.11.3"
testImplementation "org.testcontainers:oracle-xe:1.15.1"
}
2 changes: 1 addition & 1 deletion ktorm-support-postgresql/ktorm-support-postgresql.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ dependencies {

testImplementation project(path: ":ktorm-core", configuration: "testOutput")
testImplementation "org.postgresql:postgresql:42.2.5"
testImplementation "org.testcontainers:postgresql:1.11.3"
testImplementation "org.testcontainers:postgresql:1.15.1"
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@ public open class PostgreSqlFormatter(
return expr
}

override fun visitSelect(expr: SelectExpression): SelectExpression {
super.visitSelect(expr)
if (expr.extraProperties[SKIP_LOCKED] == true) {
writeKeyword("skip locked ")
}
return expr
}

protected open fun visitInsertOrUpdate(expr: InsertOrUpdateExpression): InsertOrUpdateExpression {
writeKeyword("insert into ")
visitTable(expr.table)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2018-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.ktorm.support.postgresql

import org.ktorm.dsl.Query
import org.ktorm.entity.EntitySequence
import org.ktorm.expression.SelectExpression
import org.ktorm.expression.UnionExpression
import org.ktorm.schema.BaseTable

internal const val SKIP_LOCKED = "skipLocked"

/**
* Indicate that this query should skip locked records, the generated SQL would be `select ... skip locked`.
*/
public fun Query.skipLocked(): Query {
val expr = when (expression) {
is SelectExpression ->
(expression as SelectExpression)
.copy(extraProperties = expression.extraProperties + (SKIP_LOCKED to true))
is UnionExpression ->
throw IllegalStateException("SELECT SKIP LOCKS is not supported in a union expression.")
}

return this.withExpression(expr)
}

/**
* Indicate that the generated query should skip locked records, the generated SQL would be `select ... skip locked`.
*/
public fun <E : Any, T : BaseTable<E>> EntitySequence<E, T>.skipLocked(): EntitySequence<E, T> {
return this.withExpression(expression.copy(extraProperties = expression.extraProperties + (SKIP_LOCKED to true)))
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package org.ktorm.support.postgresql

import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.CoreMatchers.nullValue
import org.junit.Assert.assertThat
import org.junit.Assert.*
import org.junit.ClassRule
import org.junit.Test
import org.ktorm.BaseTest
import org.ktorm.database.Database
import org.ktorm.database.TransactionIsolation
import org.ktorm.database.use
import org.ktorm.dsl.*
import org.ktorm.entity.*
Expand All @@ -17,19 +18,17 @@ import org.ktorm.schema.Table
import org.ktorm.schema.int
import org.ktorm.schema.varchar
import org.testcontainers.containers.PostgreSQLContainer
import org.testcontainers.utility.DockerImageName
import java.time.LocalDate
import java.util.concurrent.ExecutionException
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import java.util.concurrent.*

/**
* Created by vince on Feb 13, 2019.
*/
class PostgreSqlTest : BaseTest() {

companion object {
class KPostgreSqlContainer : PostgreSQLContainer<KPostgreSqlContainer>()
class KPostgreSqlContainer : PostgreSQLContainer<KPostgreSqlContainer>("postgres:13.1-alpine")

@ClassRule
@JvmField
Expand Down Expand Up @@ -493,4 +492,48 @@ class PostgreSqlTest : BaseTest() {

assertThat(count, equalTo(1))
}

@Test
fun testSelectForUpdateSkipLocked() {
val readyToTestSkipLocksLatch = CountDownLatch(1)
val testSkipLocksDoneLatch = CountDownLatch(1)

val skippedFuture = Executors.newSingleThreadExecutor().submit {
assertTrue(readyToTestSkipLocksLatch.await(5, TimeUnit.SECONDS))
val employees = database.useTransaction(isolation = TransactionIsolation.REPEATABLE_READ) {
database
.sequenceOf(Employees, withReferences = false)
.filter { it.id eq 1 }
.forUpdate()
.skipLocked()
.toList()
}
testSkipLocksDoneLatch.countDown()
if (employees.isNotEmpty()) {
throw java.lang.IllegalStateException("Entry should have been skipped due to being locked.")
}
}

val selectedFuture = Executors.newSingleThreadExecutor().submit {
val employees = database.useTransaction(isolation = TransactionIsolation.REPEATABLE_READ) {
val employeeList = database
.sequenceOf(Employees, withReferences = false)
.filter { it.id eq 1 }
.forUpdate()
.skipLocked()
.toList()

readyToTestSkipLocksLatch.countDown()
assertTrue(testSkipLocksDoneLatch.await(10, TimeUnit.SECONDS))
employeeList
}
if (employees.size != 1) {
throw java.lang.IllegalStateException("Entry should be available.")
}
}

assertNull(selectedFuture.get(5, TimeUnit.SECONDS))
assertNull(skippedFuture.get(5, TimeUnit.SECONDS))

}
}
2 changes: 1 addition & 1 deletion ktorm-support-sqlserver/ktorm-support-sqlserver.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ dependencies {
api "com.microsoft.sqlserver:mssql-jdbc:7.2.2.jre8"

testImplementation project(path: ":ktorm-core", configuration: "testOutput")
testImplementation "org.testcontainers:mssqlserver:1.11.3"
testImplementation "org.testcontainers:mssqlserver:1.15.1"
}
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载