diff --git a/CHANGELOG.md b/CHANGELOG.md index 508ad48..3edceeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,27 @@ - Date format: YYYY-MM-dd +## v1.3.0 / 2024-04-16 + +### All + +* Update `Kotlin`'s version to `1.9.23` + +### sqllin-dsl + +* Update `kotlinx.coroutines`'s version to `1.8.0` +* Update `kotlinx.serialization`'s version to `1.6.3` +* Modify the SQL statements' splicing method, that fixed the [issue#77](https://github.com/ctripcorp/SQLlin/issues/77) that users can't read/write special symbols as the values in SQL statements. +* Performance optimization, use `ArrayDeque` to replace the LinkedList for SQL statements management (self-implemented) + +### sqllin-driver + +* Update the `sqlite-jdbc`'s version to `3.45.3.0` + +### sqllin-processor + +* Update `KSP`'s version to `1.9.23-1.0.20` + ## v1.2.4 / 2024-01-05 ### All diff --git a/gradle.properties b/gradle.properties index 1aee745..2b48f4d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,10 @@ -VERSION=1.2.4 +VERSION=1.3.0 GROUP=com.ctrip.kotlin -kotlinVersion=1.9.22 -kspVersion=1.9.22-1.0.16 -serializationVersion=1.6.2 -coroutinesVersion=1.7.3 +kotlinVersion=1.9.23 +kspVersion=1.9.23-1.0.20 +serializationVersion=1.6.3 +coroutinesVersion=1.8.0 androidxAnnotationVersion=1.7.1 #Maven Publish Information diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6c27e92..e60ae3d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Tue Mar 08 15:11:46 CST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME \ No newline at end of file diff --git a/sqllin-driver/build.gradle.kts b/sqllin-driver/build.gradle.kts index af9b2c2..11501fa 100644 --- a/sqllin-driver/build.gradle.kts +++ b/sqllin-driver/build.gradle.kts @@ -95,7 +95,7 @@ kotlin { val jvmMain by getting { dependencies { - implementation("org.xerial:sqlite-jdbc:3.44.1.0") + implementation("org.xerial:sqlite-jdbc:3.45.3.0") } } } diff --git a/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/AndroidDatabaseConnection.kt b/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/AndroidDatabaseConnection.kt index ed60834..bb1e9ba 100644 --- a/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/AndroidDatabaseConnection.kt +++ b/sqllin-driver/src/androidMain/kotlin/com/ctrip/sqllin/driver/AndroidDatabaseConnection.kt @@ -25,17 +25,17 @@ import android.database.sqlite.SQLiteDatabase internal class AndroidDatabaseConnection(private val database: SQLiteDatabase) : DatabaseConnection { - override fun execSQL(sql: String, bindParams: Array?) = + override fun execSQL(sql: String, bindParams: Array?) = if (bindParams == null) database.execSQL(sql) else database.execSQL(sql, bindParams) - override fun executeInsert(sql: String, bindParams: Array?) = execSQL(sql, bindParams) + override fun executeInsert(sql: String, bindParams: Array?) = execSQL(sql, bindParams) - override fun executeUpdateDelete(sql: String, bindParams: Array?) = execSQL(sql, bindParams) + override fun executeUpdateDelete(sql: String, bindParams: Array?) = execSQL(sql, bindParams) - override fun query(sql: String, bindParams: Array?): CommonCursor = AndroidCursor(database.rawQuery(sql, bindParams)) + override fun query(sql: String, bindParams: Array?): CommonCursor = AndroidCursor(database.rawQuery(sql, bindParams)) override fun beginTransaction() = database.beginTransaction() override fun endTransaction() = database.endTransaction() diff --git a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/DatabaseConnection.kt b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/DatabaseConnection.kt index 2031d63..98a24a5 100644 --- a/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/DatabaseConnection.kt +++ b/sqllin-driver/src/commonMain/kotlin/com/ctrip/sqllin/driver/DatabaseConnection.kt @@ -23,11 +23,11 @@ package com.ctrip.sqllin.driver public interface DatabaseConnection { - public fun execSQL(sql: String, bindParams: Array? = null) - public fun executeInsert(sql: String, bindParams: Array? = null) - public fun executeUpdateDelete(sql: String, bindParams: Array? = null) + public fun execSQL(sql: String, bindParams: Array? = null) + public fun executeInsert(sql: String, bindParams: Array? = null) + public fun executeUpdateDelete(sql: String, bindParams: Array? = null) - public fun query(sql: String, bindParams: Array? = null): CommonCursor + public fun query(sql: String, bindParams: Array? = null): CommonCursor public fun beginTransaction() public fun setTransactionSuccessful() diff --git a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/AbstractJdbcDatabaseConnection.kt b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/AbstractJdbcDatabaseConnection.kt index 9a4b5ab..da682a4 100644 --- a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/AbstractJdbcDatabaseConnection.kt +++ b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/AbstractJdbcDatabaseConnection.kt @@ -29,7 +29,7 @@ internal abstract class AbstractJdbcDatabaseConnection : DatabaseConnection { abstract fun createStatement(sql: String): PreparedStatement - protected fun bindParamsToSQL(sql: String, bindParams: Array?): PreparedStatement = createStatement(sql).apply { + protected fun bindParamsToSQL(sql: String, bindParams: Array?): PreparedStatement = createStatement(sql).apply { bindParams?.run { require(isNotEmpty()) { "Empty bindArgs" } forEachIndexed { index, any -> diff --git a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/ConcurrentDatabaseConnection.kt b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/ConcurrentDatabaseConnection.kt index 85ce10a..801ee57 100644 --- a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/ConcurrentDatabaseConnection.kt +++ b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/ConcurrentDatabaseConnection.kt @@ -28,19 +28,19 @@ internal class ConcurrentDatabaseConnection(private val delegateConnection: Data private val accessLock = ReentrantLock() - override fun execSQL(sql: String, bindParams: Array?) = accessLock.withLock { + override fun execSQL(sql: String, bindParams: Array?) = accessLock.withLock { delegateConnection.execSQL(sql, bindParams) } - override fun executeInsert(sql: String, bindParams: Array?) = accessLock.withLock { + override fun executeInsert(sql: String, bindParams: Array?) = accessLock.withLock { delegateConnection.executeInsert(sql, bindParams) } - override fun executeUpdateDelete(sql: String, bindParams: Array?) = accessLock.withLock { + override fun executeUpdateDelete(sql: String, bindParams: Array?) = accessLock.withLock { delegateConnection.executeUpdateDelete(sql, bindParams) } - override fun query(sql: String, bindParams: Array?): CommonCursor = accessLock.withLock { + override fun query(sql: String, bindParams: Array?): CommonCursor = accessLock.withLock { delegateConnection.query(sql, bindParams) } diff --git a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/JdbcDatabaseConnection.kt b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/JdbcDatabaseConnection.kt index abfa2a1..96893a2 100644 --- a/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/JdbcDatabaseConnection.kt +++ b/sqllin-driver/src/jvmMain/kotlin/com/ctrip/sqllin/driver/JdbcDatabaseConnection.kt @@ -29,25 +29,25 @@ import java.util.concurrent.atomic.AtomicBoolean internal class JdbcDatabaseConnection(private val connection: Connection) : AbstractJdbcDatabaseConnection() { - override fun execSQL(sql: String, bindParams: Array?) { + override fun execSQL(sql: String, bindParams: Array?) { bindParamsToSQL(sql, bindParams).use { it.execute() } } - override fun executeInsert(sql: String, bindParams: Array?) { + override fun executeInsert(sql: String, bindParams: Array?) { executeUpdate(sql, bindParams) } - override fun executeUpdateDelete(sql: String, bindParams: Array?) { + override fun executeUpdateDelete(sql: String, bindParams: Array?) { executeUpdate(sql, bindParams) } - private fun executeUpdate(sql: String, bindParams: Array?): Int = bindParamsToSQL(sql, bindParams).use { + private fun executeUpdate(sql: String, bindParams: Array?): Int = bindParamsToSQL(sql, bindParams).use { it.executeUpdate() } - override fun query(sql: String, bindParams: Array?): CommonCursor { + override fun query(sql: String, bindParams: Array?): CommonCursor { val statement = connection.prepareStatement(sql) bindParams?.forEachIndexed { index, str -> str?.let { diff --git a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/ConcurrentDatabaseConnection.kt b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/ConcurrentDatabaseConnection.kt index 4838b20..5faee17 100644 --- a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/ConcurrentDatabaseConnection.kt +++ b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/ConcurrentDatabaseConnection.kt @@ -30,19 +30,19 @@ internal class ConcurrentDatabaseConnection( private val accessLock = Lock() - override fun execSQL(sql: String, bindParams: Array?) = accessLock.withLock { + override fun execSQL(sql: String, bindParams: Array?) = accessLock.withLock { delegateConnection.execSQL(sql, bindParams) } - override fun executeInsert(sql: String, bindParams: Array?) = accessLock.withLock { + override fun executeInsert(sql: String, bindParams: Array?) = accessLock.withLock { delegateConnection.executeInsert(sql, bindParams) } - override fun executeUpdateDelete(sql: String, bindParams: Array?) = accessLock.withLock { + override fun executeUpdateDelete(sql: String, bindParams: Array?) = accessLock.withLock { delegateConnection.executeUpdateDelete(sql, bindParams) } - override fun query(sql: String, bindParams: Array?): CommonCursor = accessLock.withLock { + override fun query(sql: String, bindParams: Array?): CommonCursor = accessLock.withLock { delegateConnection.query(sql, bindParams) } diff --git a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/NativeDatabaseConnection.kt b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/NativeDatabaseConnection.kt index 70e472d..94ed467 100644 --- a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/NativeDatabaseConnection.kt +++ b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/NativeDatabaseConnection.kt @@ -25,7 +25,7 @@ internal abstract class NativeDatabaseConnection : DatabaseConnection { abstract fun createStatement(sql: String): SQLiteStatement - protected fun bindParamsToSQL(sql: String, bindParams: Array?): SQLiteStatement = createStatement(sql).apply { + protected fun bindParamsToSQL(sql: String, bindParams: Array?): SQLiteStatement = createStatement(sql).apply { bindParams?.run { require(isNotEmpty()) { "Empty bindArgs" } forEachIndexed { index, any -> diff --git a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/RealDatabaseConnection.kt b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/RealDatabaseConnection.kt index eb641b1..d9b3175 100644 --- a/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/RealDatabaseConnection.kt +++ b/sqllin-driver/src/nativeMain/kotlin/com/ctrip/sqllin/driver/RealDatabaseConnection.kt @@ -37,7 +37,7 @@ internal class RealDatabaseConnection( private data class Transaction(val isSuccessful: Boolean) - override fun execSQL(sql: String, bindParams: Array?) = + override fun execSQL(sql: String, bindParams: Array?) = if (bindParams == null) { database.rawExecSql(sql) } else { @@ -49,7 +49,7 @@ internal class RealDatabaseConnection( } } - override fun executeInsert(sql: String, bindParams: Array?) { + override fun executeInsert(sql: String, bindParams: Array?) { val statement = bindParamsToSQL(sql, bindParams) try { statement.executeInsert() @@ -58,7 +58,7 @@ internal class RealDatabaseConnection( } } - override fun executeUpdateDelete(sql: String, bindParams: Array?) { + override fun executeUpdateDelete(sql: String, bindParams: Array?) { val statement = bindParamsToSQL(sql, bindParams) try { statement.executeUpdateDelete() @@ -67,7 +67,7 @@ internal class RealDatabaseConnection( } } - override fun query(sql: String, bindParams: Array?): CommonCursor { + override fun query(sql: String, bindParams: Array?): CommonCursor { val statement = createStatement(sql) bindParams?.forEachIndexed { index, str -> str?.let { diff --git a/sqllin-dsl/doc/getting-start-cn.md b/sqllin-dsl/doc/getting-start-cn.md index 91c0687..5523dfe 100644 --- a/sqllin-dsl/doc/getting-start-cn.md +++ b/sqllin-dsl/doc/getting-start-cn.md @@ -14,7 +14,7 @@ plugins { id("com.google.devtools.ksp") } -val sqllinVersion = "1.2.4" +val sqllinVersion = "1.3.0" kotlin { // ...... diff --git a/sqllin-dsl/doc/getting-start.md b/sqllin-dsl/doc/getting-start.md index 6c1c245..69c0c55 100644 --- a/sqllin-dsl/doc/getting-start.md +++ b/sqllin-dsl/doc/getting-start.md @@ -16,7 +16,7 @@ plugins { id("com.google.devtools.ksp") } -val sqllinVersion = "1.2.4" +val sqllinVersion = "1.3.0" kotlin { // ...... @@ -30,10 +30,10 @@ kotlin { implementation("com.ctrip.kotlin:sqllin-driver:$sqllinVersion") // The sqllin-dsl serialization and deserialization depends on kotlinx-serialization - implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.5.1") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3") // Since 1.2.2, sqllin-dsl depends on kotlinx.coroutines - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0") } } // ...... diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/DatabaseScope.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/DatabaseScope.kt index 41b2d9d..bc56333 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/DatabaseScope.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/DatabaseScope.kt @@ -86,8 +86,8 @@ public class DatabaseScope internal constructor( } private fun addSelectStatement(statement: SelectStatement) { - if (unionSelectStatementGroupStack.isNotEmpty) - (unionSelectStatementGroupStack.top as UnionSelectStatementGroup).addSelectStatement(statement) + if (unionSelectStatementGroupStack.isNotEmpty()) + (unionSelectStatementGroupStack.last() as UnionSelectStatementGroup).addSelectStatement(statement) else addStatement(statement) } @@ -124,7 +124,7 @@ public class DatabaseScope internal constructor( */ public infix fun Table<*>.DELETE(x: X) { - val statement = Delete.deleteAllEntity(this, databaseConnection) + val statement = Delete.deleteAllEntities(this, databaseConnection) addStatement(statement) } @@ -223,9 +223,9 @@ public class DatabaseScope internal constructor( * The 'UNION' clause of Select. */ - private val unionSelectStatementGroupStack by lazy { Stack>() } + private val unionSelectStatementGroupStack by lazy { ArrayDeque>() } - private fun getSelectStatementGroup(): StatementContainer = unionSelectStatementGroupStack.top ?: transactionStatementsGroup ?: executiveEngine + private fun getSelectStatementGroup(): StatementContainer = unionSelectStatementGroupStack.lastOrNull() ?: transactionStatementsGroup ?: executiveEngine public inline fun Table.UNION(block: Table.(Table) -> Unit): FinalSelectStatement { beginUnion() @@ -252,16 +252,16 @@ public class DatabaseScope internal constructor( } public fun beginUnion() { - unionSelectStatementGroupStack.push(UnionSelectStatementGroup()) + unionSelectStatementGroupStack.add(UnionSelectStatementGroup()) } public fun createUnionSelectStatement(isUnionAll: Boolean): FinalSelectStatement { - check(unionSelectStatementGroupStack.isNotEmpty) { "Please invoke the 'beginUnion' before you invoke this function!!!" } - return (unionSelectStatementGroupStack.top as UnionSelectStatementGroup).unionStatements(isUnionAll) + check(unionSelectStatementGroupStack.isNotEmpty()) { "Please invoke the 'beginUnion' before you invoke this function!!!" } + return (unionSelectStatementGroupStack.last() as UnionSelectStatementGroup).unionStatements(isUnionAll) } public fun endUnion(selectStatement: SelectStatement?) { - unionSelectStatementGroupStack.pop() + unionSelectStatementGroupStack.removeLast() selectStatement?.let { addSelectStatement(it) } } diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/BaseJoinClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/BaseJoinClause.kt index 81d3713..38b6e79 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/BaseJoinClause.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/BaseJoinClause.kt @@ -47,7 +47,6 @@ public sealed class JoinClause(vararg tables: Table<*>) : BaseJoinClause(* public infix fun JoinStatementWithoutCondition.ON(condition: SelectCondition): JoinSelectStatement = convertToJoinSelectStatement(condition) -@Suppress("NOTHING_TO_INLINE") public inline infix fun JoinStatementWithoutCondition.USING(clauseElement: ClauseElement): JoinSelectStatement = USING(listOf(clauseElement)) diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseBoolean.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseBoolean.kt index 9d7ff9b..3b1c00d 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseBoolean.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseBoolean.kt @@ -36,15 +36,13 @@ public class ClauseBoolean( append('.') } append(valueName) - append(' ') if (bool) - append('>') + append(" > ") else - append("<=") - append(' ') + append(" <= ") append(0) } - return SelectCondition(sql) + return SelectCondition(sql, null) } override fun hashCode(): Int = valueName.hashCode() + table.tableName.hashCode() diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseNumber.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseNumber.kt index c459986..ad7dfa4 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseNumber.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseNumber.kt @@ -81,7 +81,7 @@ public class ClauseNumber( append(symbol) } while (hasNext) } - return SelectCondition(sql) + return SelectCondition(sql, null) } internal infix fun between(range: LongRange): SelectCondition { @@ -96,7 +96,7 @@ public class ClauseNumber( append(" AND ") append(range.last) } - return SelectCondition(sql) + return SelectCondition(sql, null) } private fun appendNumber(symbol: String, number: Number): SelectCondition { @@ -111,7 +111,7 @@ public class ClauseNumber( append(' ') append(number) } - return SelectCondition(sql) + return SelectCondition(sql, null) } private fun appendNullableNumber(notNullSymbol: String, nullSymbol: String, number: Number?): SelectCondition { @@ -126,7 +126,7 @@ public class ClauseNumber( append(' ') append(number ?: "NULL") } - return SelectCondition(sql) + return SelectCondition(sql, null) } private fun appendClauseNumber(symbol: String, clauseNumber: ClauseNumber): SelectCondition { @@ -141,7 +141,7 @@ public class ClauseNumber( append('.') append(clauseNumber.valueName) } - return SelectCondition(sql) + return SelectCondition(sql, null) } override fun hashCode(): Int = valueName.hashCode() + table.tableName.hashCode() diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseString.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseString.kt index 5f27996..095a6d8 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseString.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ClauseString.kt @@ -54,12 +54,9 @@ public class ClauseString( append(valueName) append(' ') append(symbol) - append(' ') - append('\'') - append(regex) - append('\'') + append(" ?") } - return SelectCondition(sql) + return SelectCondition(sql, mutableListOf(regex)) } private fun appendString(notNullSymbol: String, nullSymbol: String, str: String?): SelectCondition { @@ -73,16 +70,12 @@ public class ClauseString( val isNull = str == null val symbol = if (isNull) nullSymbol else notNullSymbol append(symbol) - append(' ') if (str == null) append(" NULL") - else { - append('\'') - append(str) - append('\'') - } + else + append(" ?") } - return SelectCondition(sql) + return SelectCondition(sql, if (str == null) null else mutableListOf(str)) } private fun appendClauseString(symbol: String, clauseString: ClauseString): SelectCondition { @@ -97,7 +90,7 @@ public class ClauseString( append('.') append(clauseString.valueName) } - return SelectCondition(sql) + return SelectCondition(sql, null) } override fun hashCode(): Int = valueName.hashCode() + table.tableName.hashCode() diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ConditionClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ConditionClause.kt index 282074e..38ea362 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ConditionClause.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/ConditionClause.kt @@ -18,7 +18,7 @@ package com.ctrip.sqllin.dsl.sql.clause /** * Abstract clause that could link conditions, include 'WHERE' and 'HAVING' - * @author yaquai + * @author yaqiao */ public sealed class ConditionClause(private val selectCondition: SelectCondition) : SelectClause { diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/HavingClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/HavingClause.kt index f1a086b..e0991c8 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/HavingClause.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/HavingClause.kt @@ -24,7 +24,7 @@ import com.ctrip.sqllin.dsl.sql.statement.HavingSelectStatement * @author yaqiao */ -internal class HavingClause(selectCondition: SelectCondition) : ConditionClause(selectCondition) { +internal class HavingClause(val selectCondition: SelectCondition) : ConditionClause(selectCondition) { override val clauseName: String = "HAVING" } diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/InnerJoinClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/InnerJoinClause.kt index 410e019..c567d82 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/InnerJoinClause.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/InnerJoinClause.kt @@ -32,7 +32,6 @@ internal class InnerJoinClause( public fun JOIN(vararg tables: Table<*>): JoinClause = InnerJoinClause(*tables) -@Suppress("NOTHING_TO_INLINE") public inline fun INNER_JOIN(vararg tables: Table<*>): JoinClause = JOIN(*tables) internal class NaturalInnerJoinClause( @@ -44,5 +43,4 @@ internal class NaturalInnerJoinClause( public fun NATURAL_JOIN(vararg tables: Table<*>): NaturalJoinClause = NaturalInnerJoinClause(*tables) -@Suppress("NOTHING_TO_INLINE") public inline fun NATURAL_INNER_JOIN(vararg tables: Table<*>): NaturalJoinClause = NATURAL_JOIN(*tables) \ No newline at end of file diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/OrderByClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/OrderByClause.kt index 11db8f9..1100ff5 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/OrderByClause.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/OrderByClause.kt @@ -54,7 +54,6 @@ public enum class OrderByWay(internal val str: String) { public fun ORDER_BY(vararg column2Ways: Pair): OrderByClause = CompleteOrderByClause(mapOf(*column2Ways)) -@Suppress("NOTHING_TO_INLINE") public inline infix fun WhereSelectStatement.ORDER_BY(column2Way: Pair): OrderBySelectStatement = ORDER_BY(mapOf(column2Way)) @@ -63,7 +62,6 @@ public infix fun WhereSelectStatement.ORDER_BY(column2WayMap: Map HavingSelectStatement.ORDER_BY(column2Way: Pair): OrderBySelectStatement = ORDER_BY(mapOf(column2Way)) @@ -72,7 +70,6 @@ public infix fun HavingSelectStatement.ORDER_BY(column2WayMap: Map GroupBySelectStatement.ORDER_BY(column2Way: Pair): OrderBySelectStatement = ORDER_BY(mapOf(column2Way)) @@ -81,7 +78,6 @@ public infix fun GroupBySelectStatement.ORDER_BY(column2WayMap: Map JoinSelectStatement.ORDER_BY(column2Way: Pair): OrderBySelectStatement = ORDER_BY(mapOf(column2Way)) diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SelectCondition.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SelectCondition.kt index 5c0f430..49cd92e 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SelectCondition.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SelectCondition.kt @@ -23,6 +23,7 @@ package com.ctrip.sqllin.dsl.sql.clause public class SelectCondition internal constructor( internal val conditionSQL: String, + internal val parameters: MutableList?, ) { // Where condition 'OR' operator. @@ -37,6 +38,15 @@ public class SelectCondition internal constructor( append(" $symbol ") append(next.conditionSQL) } - return SelectCondition(sql) + val combinedParameters = when { + parameters == null && next.parameters != null -> next.parameters + parameters != null && next.parameters == null -> parameters + parameters == null && next.parameters == null -> null + else -> { + parameters!!.addAll(next.parameters!!) + parameters + } + } + return SelectCondition(sql, combinedParameters) } } \ No newline at end of file diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SetClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SetClause.kt index c1518eb..c9508b5 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SetClause.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/SetClause.kt @@ -25,7 +25,23 @@ public class SetClause : Clause { private val clauseBuilder = StringBuilder() - public fun append(propertyName: String, propertyValue: String?) { + internal var parameters: MutableList? = null + private set + + public fun appendString(propertyName: String, propertyValue: String?) { + clauseBuilder.append(propertyName) + if (propertyValue == null) + clauseBuilder.append("NULL,") + else { + clauseBuilder.append("?,") + val params = parameters ?: ArrayList().also { + parameters = it + } + params.add(propertyValue) + } + } + + public fun appendAny(propertyName: String, propertyValue: Any?) { clauseBuilder .append(propertyName) .append('=') diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/WhereClause.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/WhereClause.kt index 6408e21..a5fdce3 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/WhereClause.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/clause/WhereClause.kt @@ -26,7 +26,9 @@ import com.ctrip.sqllin.dsl.sql.statement.WhereSelectStatement * @author yaqiao */ -public class WhereClause internal constructor(selectCondition: SelectCondition) : ConditionClause(selectCondition) { +public class WhereClause internal constructor( + internal val selectCondition: SelectCondition, +) : ConditionClause(selectCondition) { override val clauseName: String = "WHERE" } @@ -42,7 +44,7 @@ public infix fun UpdateStatementWithoutWhereClause.WHERE(condition: Selec val statement = UpdateDeleteStatement(buildString { append(sqlStr) append(WhereClause(condition).clauseStr) - }, connection) + }, connection, condition.parameters) statementContainer changeLastStatement statement return statement.sqlStr } \ No newline at end of file diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/AbstractValuesEncoder.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/AbstractValuesEncoder.kt index 430c890..de1067d 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/AbstractValuesEncoder.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/AbstractValuesEncoder.kt @@ -33,6 +33,7 @@ internal abstract class AbstractValuesEncoder : AbstractEncoder() { final override val serializersModule: SerializersModule = EmptySerializersModule() protected abstract val sqlStrBuilder: StringBuilder + abstract val parameters: MutableList protected abstract fun StringBuilder.appendTail(): StringBuilder @@ -49,9 +50,7 @@ internal abstract class AbstractValuesEncoder : AbstractEncoder() { return true } - override fun encodeBoolean(value: Boolean) { - sqlStrBuilder.append(if (value) 1 else 0).appendTail() - } + override fun encodeBoolean(value: Boolean) = encodeByte(if (value) 1 else 0) override fun encodeByte(value: Byte) { sqlStrBuilder.append(value).appendTail() @@ -69,20 +68,11 @@ internal abstract class AbstractValuesEncoder : AbstractEncoder() { sqlStrBuilder.append(value).appendTail() } - override fun encodeChar(value: Char) { - sqlStrBuilder - .append('\'') - .append(value) - .append('\'') - .appendTail() - } + override fun encodeChar(value: Char) = encodeString(value.toString()) override fun encodeString(value: String) { - sqlStrBuilder - .append('\'') - .append(value) - .append('\'') - .appendTail() + sqlStrBuilder.append('?').appendTail() + parameters.add(value) } override fun encodeFloat(value: Float) { @@ -93,7 +83,5 @@ internal abstract class AbstractValuesEncoder : AbstractEncoder() { sqlStrBuilder.append(value).appendTail() } - override fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int) { - sqlStrBuilder.append(index).appendTail() - } + override fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int) = encodeInt(index) } \ No newline at end of file diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/EncodeEntities2SQL.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/EncodeEntities2SQL.kt index d23d577..aa3a7ac 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/EncodeEntities2SQL.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/EncodeEntities2SQL.kt @@ -27,7 +27,7 @@ import kotlinx.serialization.descriptors.SerialDescriptor * @author yaqiao */ -internal fun encodeEntities2InsertValues(serializer: SerializationStrategy, values: Iterable): String = buildString { +internal fun encodeEntities2InsertValues(serializer: SerializationStrategy, values: Iterable, parameters: MutableList): String = buildString { append('(') appendDBColumnName(serializer.descriptor) append(')') @@ -35,7 +35,7 @@ internal fun encodeEntities2InsertValues(serializer: SerializationStrategy encodeEntities2InsertValues(serializer: SerializationStrategy encodeEntities2UpdateValues(serializer: SerializationStrategy, values: Iterable): List = - values.asSequence().map { - UpdateValuesEncoder().apply { - encodeSerializableValue(serializer, it) - }.valuesSQL - }.toList() - @OptIn(ExperimentalSerializationApi::class) internal infix fun StringBuilder.appendDBColumnName(descriptor: SerialDescriptor) { for (i in 0 ..< descriptor.elementsCount) { diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/InsertValuesEncoder.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/InsertValuesEncoder.kt index 76789ba..6d3d94d 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/InsertValuesEncoder.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/InsertValuesEncoder.kt @@ -21,7 +21,9 @@ package com.ctrip.sqllin.dsl.sql.compiler * @author yaqiao */ -internal class InsertValuesEncoder : AbstractValuesEncoder() { +internal class InsertValuesEncoder( + override val parameters: MutableList, +) : AbstractValuesEncoder() { override val sqlStrBuilder = StringBuilder("(") diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/UpdateValuesEncoder.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/UpdateValuesEncoder.kt deleted file mode 100644 index e287074..0000000 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/compiler/UpdateValuesEncoder.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2022 Ctrip.com. - * - * 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 com.ctrip.sqllin.dsl.sql.compiler - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.descriptors.SerialDescriptor - -/** - * Encode the object to UPDATE SQL statement - * @author yaqiao - */ - -@OptIn(ExperimentalSerializationApi::class) -internal class UpdateValuesEncoder : AbstractValuesEncoder() { - - override val sqlStrBuilder = StringBuilder() - - override fun encodeElement(descriptor: SerialDescriptor, index: Int): Boolean { - super.encodeElement(descriptor, index) - val elementName = descriptor.getElementName(index) - sqlStrBuilder.append(elementName).append(" = ") - return true - } - - override fun StringBuilder.appendTail(): StringBuilder { - if (elementsIndex < elementsCount - 1) - append(',') - return this - } -} \ No newline at end of file diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Delete.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Delete.kt index e52ae04..a921dc3 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Delete.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Delete.kt @@ -37,14 +37,14 @@ internal object Delete : Operation { buildBaseDeleteStatement(table) append(whereClause.clauseStr) } - return UpdateDeleteStatement(sql, connection) + return UpdateDeleteStatement(sql, connection, whereClause.selectCondition.parameters) } - fun deleteAllEntity(table: Table<*>, connection: DatabaseConnection): SingleStatement { + fun deleteAllEntities(table: Table<*>, connection: DatabaseConnection): SingleStatement { val sql = buildString { buildBaseDeleteStatement(table) } - return UpdateDeleteStatement(sql, connection) + return UpdateDeleteStatement(sql, connection, null) } private fun StringBuilder.buildBaseDeleteStatement(table: Table<*>) { diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Insert.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Insert.kt index c672458..796f2e8 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Insert.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Insert.kt @@ -33,12 +33,13 @@ internal object Insert : Operation { get() = "INSERT INTO " fun insert(table: Table, connection: DatabaseConnection, entities: Iterable): SingleStatement { + val parameters = ArrayList() val sql = buildString { append(sqlStr) append(table.tableName) append(' ') - append(encodeEntities2InsertValues(table.kSerializer(), entities)) + append(encodeEntities2InsertValues(table.kSerializer(), entities, parameters)) } - return InsertStatement(sql, connection) + return InsertStatement(sql, connection, parameters) } } \ No newline at end of file diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Select.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Select.kt index b4ffaea..8768481 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Select.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Select.kt @@ -41,7 +41,7 @@ internal object Select : Operation { connection: DatabaseConnection, container: StatementContainer, ): WhereSelectStatement = - WhereSelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container) + WhereSelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container, clause.selectCondition.parameters) fun select( table: Table, @@ -51,7 +51,7 @@ internal object Select : Operation { connection: DatabaseConnection, container: StatementContainer, ): OrderBySelectStatement = - OrderBySelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container) + OrderBySelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container, mutableListOf()) fun select( table: Table, @@ -61,7 +61,7 @@ internal object Select : Operation { connection: DatabaseConnection, container: StatementContainer, ): LimitSelectStatement = - LimitSelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container) + LimitSelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container, null) fun select( table: Table, @@ -71,7 +71,7 @@ internal object Select : Operation { connection: DatabaseConnection, container: StatementContainer, ): GroupBySelectStatement = - GroupBySelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container) + GroupBySelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container, null) fun select( table: Table<*>, @@ -81,7 +81,7 @@ internal object Select : Operation { connection: DatabaseConnection, container: StatementContainer, ) : JoinSelectStatement = - JoinSelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container) + JoinSelectStatement(buildSQL(table, clause, isDistinct, deserializer), deserializer, connection, container, null) fun select( table: Table<*>, @@ -130,6 +130,6 @@ internal object Select : Operation { append(" FROM ") append(table.tableName) } - return FinalSelectStatement(sql, deserializer, connection, container) + return FinalSelectStatement(sql, deserializer, connection, container, null) } } \ No newline at end of file diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Update.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Update.kt index 5133fd1..7013327 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Update.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/operation/Update.kt @@ -44,6 +44,6 @@ internal object Update : Operation { append(" SET ") append(clause.finalize()) } - return UpdateStatementWithoutWhereClause(sql, container, connection) + return UpdateStatementWithoutWhereClause(sql, container, connection, clause.parameters) } } \ No newline at end of file diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/DatabaseExecuteEngine.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/DatabaseExecuteEngine.kt index f21bd94..dd98d59 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/DatabaseExecuteEngine.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/DatabaseExecuteEngine.kt @@ -25,25 +25,23 @@ internal class DatabaseExecuteEngine( private val enableSimpleSQLLog: Boolean, ) : StatementContainer { - private lateinit var statementsLinkedList: StatementLinkedList + private val statementList = ArrayDeque() override infix fun changeLastStatement(statement: SingleStatement) { - if (statementsLinkedList.lastStatement is UpdateStatementWithoutWhereClause<*> - || statementsLinkedList.lastStatement is SelectStatement<*>) - statementsLinkedList.resetLastStatement(statement) - else + if (statementList.lastOrNull() is UpdateStatementWithoutWhereClause<*> + || statementList.lastOrNull() is SelectStatement<*>) { + statementList.removeLast() + statementList.add(statement) + } else throw IllegalStateException("Current statement can't append clause.") } infix fun addStatement(statement: ExecutableStatement) { - if (::statementsLinkedList.isInitialized) - statementsLinkedList.addStatement(statement) - else - statementsLinkedList = StatementLinkedList(statement) + statementList.add(statement) } fun executeAllStatement() { - statementsLinkedList.forEach { + statementList.forEach { when (it) { is SingleStatement -> { if (enableSimpleSQLLog) diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/JoinStatementWithoutCondition.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/JoinStatementWithoutCondition.kt index 9761c19..18630e9 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/JoinStatementWithoutCondition.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/JoinStatementWithoutCondition.kt @@ -46,7 +46,7 @@ public class JoinStatementWithoutCondition internal constructor( append(symbol) } while (hasNext) } - val joinStatement = JoinSelectStatement(sql, deserializer, connection, container) + val joinStatement = JoinSelectStatement(sql, deserializer, connection, container, null) addSelectStatement(joinStatement) return joinStatement } @@ -57,7 +57,7 @@ public class JoinStatementWithoutCondition internal constructor( append(" ON ") append(condition.conditionSQL) } - val joinStatement = JoinSelectStatement(sql, deserializer, connection, container) + val joinStatement = JoinSelectStatement(sql, deserializer, connection, container, condition.parameters) addSelectStatement(joinStatement) return joinStatement } diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/Node.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/Node.kt deleted file mode 100644 index f9420b2..0000000 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/Node.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2022 Ctrip.com. - * - * 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 com.ctrip.sqllin.dsl.sql.statement - -/** - * A sample data struct that has two pointers - * @author yaqiao - */ - -internal class Node( - val element: T, - var pre: Node? = null, - var next: Node? = null, -) \ No newline at end of file diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/OtherStatement.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/OtherStatement.kt index d6c3eaf..0a3cae2 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/OtherStatement.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/OtherStatement.kt @@ -27,20 +27,23 @@ public class UpdateStatementWithoutWhereClause internal constructor( preSQLStr: String, internal val statementContainer: StatementContainer, internal val connection: DatabaseConnection, + override val parameters: MutableList?, ) : SingleStatement(preSQLStr) { - public override fun execute(): Unit = connection.executeUpdateDelete(sqlStr) + public override fun execute(): Unit = connection.executeUpdateDelete(sqlStr, params) } public class UpdateDeleteStatement internal constructor( sqlStr: String, private val connection: DatabaseConnection, + override val parameters: MutableList?, ) : SingleStatement(sqlStr) { - public override fun execute(): Unit = connection.executeUpdateDelete(sqlStr) + public override fun execute(): Unit = connection.executeUpdateDelete(sqlStr, params) } public class InsertStatement internal constructor( sqlStr: String, private val connection: DatabaseConnection, + override val parameters: MutableList, ) : SingleStatement(sqlStr) { - public override fun execute(): Unit = connection.executeInsert(sqlStr) + public override fun execute(): Unit = connection.executeInsert(sqlStr, params) } diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/SelectStatement.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/SelectStatement.kt index 666bf28..431182a 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/SelectStatement.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/SelectStatement.kt @@ -34,6 +34,7 @@ public sealed class SelectStatement( internal val deserializer: DeserializationStrategy, internal val connection: DatabaseConnection, internal val container: StatementContainer, + final override val parameters: MutableList?, ) : SingleStatement(sqlStr) { @Volatile @@ -43,7 +44,7 @@ public sealed class SelectStatement( private var cursor: CommonCursor? = null final override fun execute() { - cursor = connection.query(sqlStr) + cursor = connection.query(sqlStr, params) } @OptIn(ExperimentalStdlibApi::class) @@ -71,7 +72,7 @@ public sealed class SelectStatement( append(" CROSS JOIN ") append(table.tableName) } - return FinalSelectStatement(sql, newDeserializer, connection, container) + return FinalSelectStatement(sql, newDeserializer, connection, container, parameters) } } @@ -80,16 +81,17 @@ public class WhereSelectStatement internal constructor( deserializer: DeserializationStrategy, connection: DatabaseConnection, container: StatementContainer, -) : SelectStatement(sqlStr, deserializer, connection, container) { + parameters: MutableList?, +) : SelectStatement(sqlStr, deserializer, connection, container, parameters) { internal infix fun appendToLimit(clause: LimitClause): LimitSelectStatement = - LimitSelectStatement(buildSQL(clause), deserializer, connection, container) + LimitSelectStatement(buildSQL(clause), deserializer, connection, container, parameters) internal infix fun appendToOrderBy(clause: OrderByClause): OrderBySelectStatement = - OrderBySelectStatement(buildSQL(clause), deserializer, connection, container) + OrderBySelectStatement(buildSQL(clause), deserializer, connection, container, parameters) internal infix fun appendToGroupBy(clause: GroupByClause): GroupBySelectStatement = - GroupBySelectStatement(buildSQL(clause), deserializer, connection, container) + GroupBySelectStatement(buildSQL(clause), deserializer, connection, container, parameters) } public class JoinSelectStatement internal constructor( @@ -97,19 +99,27 @@ public class JoinSelectStatement internal constructor( deserializer: DeserializationStrategy, connection: DatabaseConnection, container: StatementContainer, -) : SelectStatement(sqlStr, deserializer, connection, container) { - - internal infix fun appendToWhere(clause: WhereClause): WhereSelectStatement = - WhereSelectStatement(buildSQL(clause), deserializer, connection, container) + parameters: MutableList?, +) : SelectStatement(sqlStr, deserializer, connection, container, parameters) { + + internal infix fun appendToWhere(clause: WhereClause): WhereSelectStatement { + val clauseParams = clause.selectCondition.parameters + val params = parameters?.also { + clauseParams?.let { p -> + it.addAll(p) + } + } ?: clauseParams + return WhereSelectStatement(buildSQL(clause), deserializer, connection, container, params) + } internal infix fun appendToLimit(clause: LimitClause): LimitSelectStatement = - LimitSelectStatement(buildSQL(clause), deserializer, connection, container) + LimitSelectStatement(buildSQL(clause), deserializer, connection, container, parameters) internal infix fun appendToOrderBy(clause: OrderByClause): OrderBySelectStatement = - OrderBySelectStatement(buildSQL(clause), deserializer, connection, container) + OrderBySelectStatement(buildSQL(clause), deserializer, connection, container, parameters) internal infix fun appendToGroupBy(clause: GroupByClause): GroupBySelectStatement = - GroupBySelectStatement(buildSQL(clause), deserializer, connection, container) + GroupBySelectStatement(buildSQL(clause), deserializer, connection, container, parameters) } public class GroupBySelectStatement internal constructor( @@ -117,13 +127,21 @@ public class GroupBySelectStatement internal constructor( deserializer: DeserializationStrategy, connection: DatabaseConnection, container: StatementContainer, -) : SelectStatement(sqlStr, deserializer, connection, container) { + parameters: MutableList?, +) : SelectStatement(sqlStr, deserializer, connection, container, parameters) { internal infix fun appendToOrderBy(clause: OrderByClause): OrderBySelectStatement = - OrderBySelectStatement(buildSQL(clause), deserializer, connection, container) + OrderBySelectStatement(buildSQL(clause), deserializer, connection, container, parameters) - internal infix fun appendToHaving(clause: HavingClause): HavingSelectStatement = - HavingSelectStatement(buildSQL(clause), deserializer, connection, container) + internal infix fun appendToHaving(clause: HavingClause): HavingSelectStatement { + val clauseParams = clause.selectCondition.parameters + val params = parameters?.also { + clauseParams?.let { p -> + it.addAll(p) + } + } ?: clauseParams + return HavingSelectStatement(buildSQL(clause), deserializer, connection, container, params) + } } public class HavingSelectStatement internal constructor( @@ -131,13 +149,14 @@ public class HavingSelectStatement internal constructor( deserializer: DeserializationStrategy, connection: DatabaseConnection, container: StatementContainer, -) : SelectStatement(sqlStr, deserializer, connection, container) { + parameters: MutableList?, +) : SelectStatement(sqlStr, deserializer, connection, container, parameters) { internal infix fun appendToOrderBy(clause: OrderByClause): OrderBySelectStatement = - OrderBySelectStatement(buildSQL(clause), deserializer, connection, container) + OrderBySelectStatement(buildSQL(clause), deserializer, connection, container, parameters) internal infix fun appendToLimit(clause: LimitClause): LimitSelectStatement = - LimitSelectStatement(buildSQL(clause), deserializer, connection, container) + LimitSelectStatement(buildSQL(clause), deserializer, connection, container, parameters) } public class OrderBySelectStatement internal constructor( @@ -145,10 +164,11 @@ public class OrderBySelectStatement internal constructor( deserializer: DeserializationStrategy, connection: DatabaseConnection, container: StatementContainer, -) : SelectStatement(sqlStr, deserializer, connection, container) { + parameters: MutableList?, +) : SelectStatement(sqlStr, deserializer, connection, container, parameters) { internal infix fun appendToLimit(clause: LimitClause): LimitSelectStatement = - LimitSelectStatement(buildSQL(clause), deserializer, connection, container) + LimitSelectStatement(buildSQL(clause), deserializer, connection, container, parameters) } public class LimitSelectStatement internal constructor( @@ -156,10 +176,11 @@ public class LimitSelectStatement internal constructor( deserializer: DeserializationStrategy, connection: DatabaseConnection, container: StatementContainer, -) : SelectStatement(sqlStr, deserializer, connection, container) { + parameters: MutableList?, +) : SelectStatement(sqlStr, deserializer, connection, container, parameters) { internal infix fun appendToFinal(clause: OffsetClause): FinalSelectStatement = - FinalSelectStatement(buildSQL(clause), deserializer, connection, container) + FinalSelectStatement(buildSQL(clause), deserializer, connection, container, parameters) } public class FinalSelectStatement internal constructor( @@ -167,4 +188,5 @@ public class FinalSelectStatement internal constructor( deserializer: DeserializationStrategy, connection: DatabaseConnection, container: StatementContainer, -) : SelectStatement(sqlStr, deserializer, connection, container) \ No newline at end of file + parameters: MutableList?, +) : SelectStatement(sqlStr, deserializer, connection, container, parameters) \ No newline at end of file diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/SingleStatement.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/SingleStatement.kt index 0377143..3463fd9 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/SingleStatement.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/SingleStatement.kt @@ -23,4 +23,10 @@ package com.ctrip.sqllin.dsl.sql.statement public sealed class SingleStatement( public val sqlStr: String, -) : ExecutableStatement +) : ExecutableStatement { + + internal abstract val parameters: MutableList? + + internal val params: Array? + get() = parameters?.toTypedArray() +} \ No newline at end of file diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/Stack.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/Stack.kt deleted file mode 100644 index e8050a8..0000000 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/Stack.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2022 Ctrip.com. - * - * 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 com.ctrip.sqllin.dsl.sql.statement - -import kotlin.concurrent.Volatile - -/** - * A sample Stack implementation - * @author yaqiao - */ - -internal class Stack { - - @Volatile - private var topNode: Node? = null - - val isEmpty - get() = topNode == null - - val isNotEmpty - get() = !isEmpty - - val top: T? - get() = topNode?.element - - fun pop(): T? { - var value: T? = null - topNode = topNode?.let { - value = it.element - val newTopNode = it.next?.apply { pre = null } - it.next = null - newTopNode - } - return value - } - - fun push(e: T) { - val newNode = Node(e) - if (isEmpty) - topNode = newNode - else { - topNode!!.pre = newNode - newNode.next = topNode - topNode = newNode - } - } -} \ No newline at end of file diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/StatementLinkedList.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/StatementLinkedList.kt deleted file mode 100644 index 77338aa..0000000 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/StatementLinkedList.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2022 Ctrip.com. - * - * 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 com.ctrip.sqllin.dsl.sql.statement - -/** - * Single LinkedList that used for store 'CompleteStatement' - * @author yaqiao - */ - -internal class StatementLinkedList(firstStatement: T) : Iterator { - - private var firstNode = Node(firstStatement) - private var lastNode = firstNode - - val lastStatement: T - get() = lastNode.element - - infix fun addStatement(statement: T) { - val node = Node(statement) - lastNode.next = node - node.pre = lastNode - lastNode = node - } - - private var forEachNode: Node? = firstNode - - override fun hasNext(): Boolean = forEachNode != null - - override fun next(): T = forEachNode?.apply { - forEachNode = next - }?.element ?: throw IllegalStateException("Engine must not be empty!!") - - infix fun resetLastStatement(statement: T) { - val secondLastNode = lastNode.pre - val isOnlyOneNode = firstNode === lastNode - lastNode.pre = null - lastNode = Node(statement) - if (isOnlyOneNode) { - firstNode = lastNode - forEachNode = lastNode - } - secondLastNode?.run { - next = lastNode - lastNode.pre = this - } - } -} \ No newline at end of file diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/TransactionStatementsGroup.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/TransactionStatementsGroup.kt index e6a39c1..ce04053 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/TransactionStatementsGroup.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/TransactionStatementsGroup.kt @@ -29,13 +29,10 @@ internal class TransactionStatementsGroup( private val enableSimpleSQLLog: Boolean, ) : ExecutableStatement, StatementContainer { - private lateinit var statementList: StatementLinkedList + private val statementList = ArrayDeque() infix fun addStatement(statement: SingleStatement) { - if (this::statementList.isInitialized) - statementList.addStatement(statement) - else - statementList = StatementLinkedList(statement) + statementList.add(statement) } override fun execute() = databaseConnection.withTransaction { @@ -47,10 +44,11 @@ internal class TransactionStatementsGroup( } override infix fun changeLastStatement(statement: SingleStatement) { - if (statementList.lastStatement is UpdateStatementWithoutWhereClause<*> - || statementList.lastStatement is SelectStatement<*>) - statementList resetLastStatement statement - else + if (statementList.lastOrNull() is UpdateStatementWithoutWhereClause<*> + || statementList.lastOrNull() is SelectStatement<*>) { + statementList.removeLast() + statementList.add(statement) + } else throw IllegalStateException("Current statement can't append clause.") } } \ No newline at end of file diff --git a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/UnionSelectStatementGroup.kt b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/UnionSelectStatementGroup.kt index 7552c37..5db43a1 100644 --- a/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/UnionSelectStatementGroup.kt +++ b/sqllin-dsl/src/commonMain/kotlin/com/ctrip/sqllin/dsl/sql/statement/UnionSelectStatementGroup.kt @@ -23,51 +23,47 @@ package com.ctrip.sqllin.dsl.sql.statement internal class UnionSelectStatementGroup : StatementContainer { - private var statementLinkedList: StatementLinkedList>? = null + private val statementList = ArrayDeque>() infix fun addSelectStatement(selectStatement: SelectStatement) { - if (statementLinkedList != null) - statementLinkedList!!.addStatement(selectStatement) - else - statementLinkedList = StatementLinkedList(selectStatement) + statementList.add(selectStatement) } internal fun unionStatements(isUnionAll: Boolean): FinalSelectStatement { - require(statementLinkedList?.hasNext() == true) { "Please write at least two 'select' statements on 'UNION' scope" } - var firstStatement: SelectStatement? = null + require(statementList.isNotEmpty()) { "Please write at least two 'select' statements on 'UNION' scope" } + var parameters: MutableList? = null val unionSqlStr = buildString { - statementLinkedList!!.run { - val unionKeyWord = if (isUnionAll) " UNION ALL " else " UNION " - do { - val next = next() - append(next.sqlStr) - val hasNext = hasNext() - if (firstStatement == null) { - firstStatement = next - if (!hasNext) - throw IllegalStateException("Please write at least two 'select' statements on 'UNION' scope") - } - if (hasNext) - append(unionKeyWord) - } while (hasNext) + check(statementList.size > 1) { "Please write at least two 'select' statements on 'UNION' scope" } + val unionKeyWord = if (isUnionAll) " UNION ALL " else " UNION " + statementList.forEachIndexed { index, statement -> + append(statement.sqlStr) + if (parameters == null) + parameters = statement.parameters + else statement.parameters?.let { + parameters!!.addAll(it) + } + if (index != statementList.lastIndex) + append(unionKeyWord) } } - return firstStatement!!.run { + return statementList.first().run { FinalSelectStatement( sqlStr = unionSqlStr, deserializer = deserializer, connection = connection, container = container, + parameters, ) } } @Suppress("UNCHECKED_CAST") override fun changeLastStatement(statement: SingleStatement) { - if (statementLinkedList?.lastStatement is SelectStatement<*>) - statementLinkedList!!.resetLastStatement(statement as SelectStatement) - else + if (statementList.lastOrNull() is SelectStatement<*>) { + statementList.removeLast() + statementList.add(statement as SelectStatement) + } else throw IllegalStateException("Current statement can't append clause") } } \ No newline at end of file diff --git a/sqllin-dsl/src/commonTest/kotlin/com/ctrip/sqllin/dsl/TestPrimitiveTypeForKSP.kt b/sqllin-dsl/src/commonTest/kotlin/com/ctrip/sqllin/dsl/TestPrimitiveTypeForKSP.kt index cc8f974..7ef58e4 100644 --- a/sqllin-dsl/src/commonTest/kotlin/com/ctrip/sqllin/dsl/TestPrimitiveTypeForKSP.kt +++ b/sqllin-dsl/src/commonTest/kotlin/com/ctrip/sqllin/dsl/TestPrimitiveTypeForKSP.kt @@ -37,7 +37,7 @@ data class TestPrimitiveTypeForKSP( val testULong: ULong, val testUShort: UShort, val testUByte: UByte, - val testBoolean: Boolean, - val testChar: Char, + val testBoolean: Boolean?, + val testChar: Char?, val testString: String, ) \ No newline at end of file diff --git a/sqllin-processor/src/main/kotlin/com/ctrip/sqllin/processor/ClauseProcessor.kt b/sqllin-processor/src/main/kotlin/com/ctrip/sqllin/processor/ClauseProcessor.kt index addb65f..d6d0d5c 100644 --- a/sqllin-processor/src/main/kotlin/com/ctrip/sqllin/processor/ClauseProcessor.kt +++ b/sqllin-processor/src/main/kotlin/com/ctrip/sqllin/processor/ClauseProcessor.kt @@ -95,7 +95,7 @@ class ClauseProcessor( val nullableSymbol = if (isNotNull) "\n" else "?\n" writer.write(nullableSymbol) writer.write(" get() = ${getSetClauseGetterValue(property)}\n") - writer.write(" set(value) = append($elementName, \"${getValueStr(property)}\")\n\n") + writer.write(" set(value) = ${appendFunction(elementName, property)}\n\n") } writer.write("}") } @@ -146,13 +146,11 @@ class ClauseProcessor( else -> null } - private fun getValueStr(property: KSPropertyDeclaration): String = when ( - property.typeName - ) { - Char::class.qualifiedName, - String::class.qualifiedName -> "'\$value'" - Boolean::class.qualifiedName -> "\${if (value) 1 else 0}" - else -> "\$value" + private fun appendFunction(elementName: String, property: KSPropertyDeclaration): String = when (property.typeName) { + Char::class.qualifiedName -> "appendString($elementName, value?.toString())" + String::class.qualifiedName -> "appendString($elementName, value)" + Boolean::class.qualifiedName -> "appendAny($elementName, value?.let { if (it) 1 else 0 })" + else -> "appendAny($elementName, value)" } private inline val KSPropertyDeclaration.typeName