1616
1717package com.ctrip.sqllin.driver
1818
19+ import com.ctrip.sqllin.driver.platform.separatorChar
20+ import kotlin.jvm.JvmInline
21+
1922/* *
2023 * SQLite extension function
2124 * @author yaqiao
@@ -62,4 +65,108 @@ public inline fun <T> DatabaseConnection.withQuery(
6265 }
6366}
6467
65- public expect fun deleteDatabase (path : DatabasePath , name : String ): Boolean
68+ public expect fun deleteDatabase (path : DatabasePath , name : String ): Boolean
69+
70+ internal infix fun DatabaseConnection.updateSynchronousMode (mode : SynchronousMode ) {
71+ val currentJournalMode = withQuery(" PRAGMA synchronous;" ) {
72+ it.next()
73+ it.getInt(0 )
74+ }
75+ if (currentJournalMode != mode.value)
76+ execSQL(" PRAGMA synchronous=${mode.value} ;" )
77+ }
78+
79+ internal infix fun DatabaseConnection.updateJournalMode (mode : JournalMode ) {
80+ val currentJournalMode = withQuery(" PRAGMA journal_mode;" ) {
81+ it.next()
82+ it.getString(0 )
83+ }
84+ if (! currentJournalMode.equals(mode.name, ignoreCase = true ))
85+ withQuery(" PRAGMA journal_mode=${mode.name} ;" ) {}
86+ }
87+
88+ internal fun DatabaseConnection.migrateIfNeeded (
89+ create : (DatabaseConnection ) -> Unit ,
90+ upgrade : (DatabaseConnection , Int , Int ) -> Unit ,
91+ version : Int ,
92+ ) = withTransaction {
93+ val initialVersion = withQuery(" PRAGMA user_version;" ) {
94+ it.next()
95+ it.getInt(0 )
96+ }
97+ if (initialVersion == 0 ) {
98+ create(this )
99+ execSQL(" PRAGMA user_version = $version ;" )
100+ } else if (initialVersion != version) {
101+ if (initialVersion > version) {
102+ throw IllegalStateException (" Database version $initialVersion newer than config version $version " )
103+ }
104+ upgrade(this , initialVersion, version)
105+ execSQL(" PRAGMA user_version = $version ;" )
106+ }
107+ }
108+
109+ internal fun DatabaseConfiguration.diskOrMemoryPath (): String =
110+ if (inMemory) {
111+ if (name.isBlank())
112+ " :memory:"
113+ else
114+ " file:$name ?mode=memory&cache=shared"
115+ } else {
116+ require(name.isNotBlank()) { " Database name cannot be blank" }
117+ getDatabaseFullPath((path as StringDatabasePath ).pathString, name)
118+ }
119+
120+ internal fun getDatabaseFullPath (dirPath : String , name : String ): String {
121+ val param = when {
122+ dirPath.isEmpty() -> name
123+ name.isEmpty() -> dirPath
124+ else -> join(dirPath, name)
125+ }
126+ return fixSlashes(param)
127+ }
128+
129+ private fun join (prefix : String , suffix : String ): String {
130+ val haveSlash = (prefix.isNotEmpty() && prefix.last() == separatorChar)
131+ || (suffix.isNotEmpty() && suffix.first() == separatorChar)
132+ return buildString {
133+ append(prefix)
134+ if (! haveSlash)
135+ append(separatorChar)
136+ append(suffix)
137+ }
138+ }
139+
140+ private fun fixSlashes (origPath : String ): String {
141+ // Remove duplicate adjacent slashes.
142+ var lastWasSlash = false
143+ val newPath = origPath.toCharArray()
144+ val length = newPath.size
145+ var newLength = 0
146+ val initialIndex = if (origPath.startsWith(" file://" , true )) 7 else 0
147+ for (i in initialIndex .. < length) {
148+ val ch = newPath[i]
149+ if (ch == separatorChar) {
150+ if (! lastWasSlash) {
151+ newPath[newLength++ ] = separatorChar
152+ lastWasSlash = true
153+ }
154+ } else {
155+ newPath[newLength++ ] = ch
156+ lastWasSlash = false
157+ }
158+ }
159+ // Remove any trailing slash (unless this is the root of the file system).
160+ if (lastWasSlash && newLength > 1 ) {
161+ newLength--
162+ }
163+
164+ // Reuse the original string if possible.
165+ return if (newLength != length) buildString(newLength) {
166+ append(newPath)
167+ setLength(newLength)
168+ } else origPath
169+ }
170+
171+ @JvmInline
172+ internal value class StringDatabasePath (val pathString : String ) : DatabasePath
0 commit comments