188865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar/* 288865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * Copyright (C) 2017 The Android Open Source Project 388865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * 488865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 588865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * you may not use this file except in compliance with the License. 688865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * You may obtain a copy of the License at 788865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * 888865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 988865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * 1088865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * Unless required by applicable law or agreed to in writing, software 1188865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 1288865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1388865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * See the License for the specific language governing permissions and 1488865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * limitations under the License. 1588865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar */ 1688865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar 1764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarpackage android.arch.persistence.room.verifier 1888865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar 1988865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyarimport columnInfo 2064db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.Context 2164db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.Entity 2264db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.Warning 2388865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyarimport java.io.File 2488865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyarimport java.sql.Connection 2588865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyarimport java.sql.DriverManager 2688865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyarimport java.sql.SQLException 2788865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyarimport java.util.UUID 2888865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyarimport javax.lang.model.element.Element 2988865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar 3088865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar/** 3188865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * Builds an in-memory version of the database and verifies the queries against it. 3288865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * This class is also used to resolve the return types. 3388865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar */ 3488865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyarclass DatabaseVerifier private constructor( 3588865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar val connection : Connection, val context : Context, val entities : List<Entity>) { 3688865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar companion object { 3788865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar /** 3888865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar * Tries to create a verifier but returns null if it cannot find the driver. 3988865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar */ 4088865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar fun create(context: Context, element: Element, entities: List<Entity>) : DatabaseVerifier? { 4188865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar return try { 4288865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar // see: https://github.com/xerial/sqlite-jdbc/issues/97 4388865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar val tmpDir = System.getProperty("java.io.tmpdir") 4488865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar if (tmpDir == null) { 45aa82fce1d73394bdc7f4c2510cf94a3572032b24Yigit Boyar context.logger.w(Warning.MISSING_JAVA_TMP_DIR, 46aa82fce1d73394bdc7f4c2510cf94a3572032b24Yigit Boyar element, DatabaseVerificaitonErrors.CANNOT_GET_TMP_JAVA_DIR) 4788865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar return null 4888865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } 4988865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar val outDir = File(tmpDir, "room-${UUID.randomUUID()}") 5088865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar outDir.mkdirs() 5188865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar outDir.deleteOnExit() 5288865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar System.setProperty("org.sqlite.tmpdir", outDir.absolutePath) 5388865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar //force load: 5488865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar Class.forName("org.sqlite.JDBC") 5588865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar val connection = DriverManager.getConnection("jdbc:sqlite::memory:") 5688865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar DatabaseVerifier(connection, context, entities) 5788865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } catch (ex : Exception) { 58aa82fce1d73394bdc7f4c2510cf94a3572032b24Yigit Boyar context.logger.w(Warning.CANNOT_CREATE_VERIFICATION_DATABASE, element, 59aa82fce1d73394bdc7f4c2510cf94a3572032b24Yigit Boyar DatabaseVerificaitonErrors.cannotCreateConnection(ex)) 6088865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar null 6188865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } 6288865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } 6388865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } 6488865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar init { 6588865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar entities.forEach { entity -> 6688865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar val stmt = connection.createStatement() 6788865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar stmt.executeUpdate(entity.createTableQuery) 6888865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } 6988865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } 7088865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar 7188865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar fun analyze(sql : String) : QueryResultInfo { 7288865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar return try { 7388865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar val stmt = connection.prepareStatement(sql) 7488865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar QueryResultInfo(stmt.columnInfo()) 7588865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } catch (ex : SQLException) { 7688865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar QueryResultInfo(emptyList(), ex) 7788865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } 7888865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar } 7977a44be4d08eeed548f01560d9d332ef24138f45Yigit Boyar 8077a44be4d08eeed548f01560d9d332ef24138f45Yigit Boyar fun closeConnection() { 8177a44be4d08eeed548f01560d9d332ef24138f45Yigit Boyar if (!connection.isClosed) { 8277a44be4d08eeed548f01560d9d332ef24138f45Yigit Boyar try { 8377a44be4d08eeed548f01560d9d332ef24138f45Yigit Boyar connection.close() 8477a44be4d08eeed548f01560d9d332ef24138f45Yigit Boyar } catch (t : Throwable) { 8577a44be4d08eeed548f01560d9d332ef24138f45Yigit Boyar //ignore. 8677a44be4d08eeed548f01560d9d332ef24138f45Yigit Boyar } 8777a44be4d08eeed548f01560d9d332ef24138f45Yigit Boyar } 8877a44be4d08eeed548f01560d9d332ef24138f45Yigit Boyar } 8988865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar} 90