<commit_before>import XCTest
#if GRDBCIPHER
    @testable import GRDBCipher
#elseif GRDBCUSTOMSQLITE
    @testable import GRDBCustomSQLite
#else
    @testable import GRDB
#endif

class StatementSelectionInfoTests : GRDBTestCase {
    
    func testSelectStatement() throws {
        let dbQueue = try makeDatabaseQueue()
        try dbQueue.inDatabase { db in
            try db.execute("CREATE TABLE foo (id INTEGER, name TEXT)")
            try db.execute("CREATE TABLE bar (id INTEGER, fooId INTEGER)")
            let statement = try db.makeSelectStatement("SELECT foo.name FROM FOO JOIN BAR ON fooId = foo.id")
            XCTAssertTrue(statement.selectionInfo.contains(anyColumnIn: ["id"], from: "foo"))
            XCTAssertTrue(statement.selectionInfo.contains(anyColumnIn: ["name"], from: "foo"))
            XCTAssertFalse(statement.selectionInfo.contains(anyColumnIn: ["id"], from: "bar"))
            XCTAssertTrue(statement.selectionInfo.contains(anyColumnIn: ["fooId"], from: "bar"))
        }
    }
    
    func testRowIdNameInSelectStatement() throws {
        let dbQueue = try makeDatabaseQueue()
        try dbQueue.inDatabase { db in
            try db.execute("CREATE TABLE foo (name TEXT)")
            do {
                let statement = try db.makeSelectStatement("SELECT rowid FROM FOO")
                XCTAssertTrue(statement.selectionInfo.contains(anyColumnIn: ["ROWID"], from: "foo"))
            }
            do {
                let statement = try db.makeSelectStatement("SELECT _ROWID_ FROM FOO")
                XCTAssertTrue(statement.selectionInfo.contains(anyColumnIn: ["ROWID"], from: "foo"))
            }
            do {
                let statement = try db.makeSelectStatement("SELECT oID FROM FOO")
                XCTAssertTrue(statement.selectionInfo.contains(anyColumnIn: ["ROWID"], from: "foo"))
            }
        }
    }
    
    func testSelectionInfoRowIds() throws {
        let dbQueue = try makeDatabaseQueue()
        try dbQueue.inDatabase { db in
            try db.execute("CREATE TABLE foo (id INTEGER PRIMARY KEY, a TEXT)")
            struct Record: TableMapping {
                static let databaseTableName = "foo"
            }
            
            // Undefined rowIds
            
            do {
                let request = Record.all()
                try XCTAssertNil(request.selectionInfo(db).rowIds)
            }
            do {
                let request = Record.filter(Column("a") == 1)
                try XCTAssertNil(request.selectionInfo(db).rowIds)
            }
            do {
                let request = Record.filter(Column("id") >= 1)
                try XCTAssertNil(request.selectionInfo(db).rowIds)
            }
            
            do {
                let request = Record.filter((Column("id") == 1) || (Column("a") == "foo"))
                try XCTAssertNil(request.selectionInfo(db).rowIds)
            }

            // No rowId
            
            do {
                let request = Record.filter(Column("id") == nil)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [])
            }

            do {
                let request = Record.filter(Column("id") === nil)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [])
            }
            
            do {
                let request = Record.filter(nil == Column("id"))
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [])
            }
            
            do {
                let request = Record.filter(nil === Column("id"))
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [])
            }
            
            do {
                let request = Record.filter((Column("id") == 1) && (Column("id") == 2))
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [])
            }
            do {
                let request = Record.filter(key: 1).filter(key: 2)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [])
            }

            // Single rowId
            
            do {
                let request = Record.filter(Column("id") == 1)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(Column("id") === 1)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(Column("id") == 1 && Column("a") == "foo")
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(Column.rowID == 1)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(1 == Column("id"))
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(1 === Column("id"))
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(1 === Column.rowID)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(key: 1)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(key: 1).filter(key: 1)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(key: 1).filter(Column("a") == "foo")
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }

            // Multiple rowIds
            
            do {
                let request = Record.filter(Column("id") == 1 || Column.rowID == 2)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1, 2])
            }
            do {
                let request = Record.filter([1, 2, 3].contains(Column("id")))
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1, 2, 3])
            }
            do {
                let request = Record.filter([1, 2, 3].contains(Column.rowID))
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1, 2, 3])
            }
            do {
                let request = Record.filter(keys: [1, 2, 3])
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1, 2, 3])
            }
        }
    }
    
    func testUpdateStatement() throws {
        let dbQueue = try makeDatabaseQueue()
        try dbQueue.inDatabase { db in
            try db.execute("CREATE TABLE foo (id INTEGER, bar TEXT, baz TEXT, qux TEXT)")
            let statement = try db.makeUpdateStatement("UPDATE foo SET bar = 'bar', baz = 'baz' WHERE id = 1")
            XCTAssertFalse(statement.invalidatesDatabaseSchemaCache)
            XCTAssertEqual(statement.databaseEventKinds.count, 1)
            guard case .update(let tableName, let columnNames) = statement.databaseEventKinds[0] else {
                XCTFail()
                return
            }
            XCTAssertEqual(tableName, "foo")
            XCTAssertEqual(columnNames, Set(["bar", "baz"]))
        }
    }
    
    func testRowIdNameInUpdateStatement() throws {
        let dbQueue = try makeDatabaseQueue()
        try dbQueue.inDatabase { db in
            try db.execute("CREATE TABLE foo (name TEXT)")
            do {
                let statement = try db.makeUpdateStatement("UPDATE foo SET rowid = 1")
                XCTAssertEqual(statement.databaseEventKinds.count, 1)
                guard case .update(let tableName, let columnNames) = statement.databaseEventKinds[0] else {
                    XCTFail()
                    return
                }
                XCTAssertEqual(tableName, "foo")
                XCTAssertEqual(columnNames, ["ROWID"])
            }
            do {<commit_msg>Disable test that fails on iOS 8.1 (SQLite 3.7.13)<commit_after>import XCTest
#if GRDBCIPHER
    @testable import GRDBCipher
#elseif GRDBCUSTOMSQLITE
    @testable import GRDBCustomSQLite
#else
    @testable import GRDB
#endif

class StatementSelectionInfoTests : GRDBTestCase {
    
    func testSelectStatement() throws {
        let dbQueue = try makeDatabaseQueue()
        try dbQueue.inDatabase { db in
            try db.execute("CREATE TABLE foo (id INTEGER, name TEXT)")
            try db.execute("CREATE TABLE bar (id INTEGER, fooId INTEGER)")
            let statement = try db.makeSelectStatement("SELECT foo.name FROM FOO JOIN BAR ON fooId = foo.id")
            XCTAssertTrue(statement.selectionInfo.contains(anyColumnIn: ["id"], from: "foo"))
            XCTAssertTrue(statement.selectionInfo.contains(anyColumnIn: ["name"], from: "foo"))
            XCTAssertFalse(statement.selectionInfo.contains(anyColumnIn: ["id"], from: "bar"))
            XCTAssertTrue(statement.selectionInfo.contains(anyColumnIn: ["fooId"], from: "bar"))
        }
    }
    
    func testRowIdNameInSelectStatement() throws {
        // Here we test that sqlite authorizer gives the "ROWID" name to
        // the rowid column, regardless of its name in the request (rowid, oid, _rowid_)
        //
        // See also testRowIdNameInUpdateStatement
        let dbQueue = try makeDatabaseQueue()
        try dbQueue.inDatabase { db in
            try db.execute("CREATE TABLE foo (name TEXT)")
            do {
                let statement = try db.makeSelectStatement("SELECT rowid FROM FOO")
                XCTAssertTrue(statement.selectionInfo.contains(anyColumnIn: ["ROWID"], from: "foo"))
            }
            do {
                let statement = try db.makeSelectStatement("SELECT _ROWID_ FROM FOO")
                XCTAssertTrue(statement.selectionInfo.contains(anyColumnIn: ["ROWID"], from: "foo"))
            }
            do {
                let statement = try db.makeSelectStatement("SELECT oID FROM FOO")
                XCTAssertTrue(statement.selectionInfo.contains(anyColumnIn: ["ROWID"], from: "foo"))
            }
        }
    }
    
    func testSelectionInfoRowIds() throws {
        let dbQueue = try makeDatabaseQueue()
        try dbQueue.inDatabase { db in
            try db.execute("CREATE TABLE foo (id INTEGER PRIMARY KEY, a TEXT)")
            struct Record: TableMapping {
                static let databaseTableName = "foo"
            }
            
            // Undefined rowIds
            
            do {
                let request = Record.all()
                try XCTAssertNil(request.selectionInfo(db).rowIds)
            }
            do {
                let request = Record.filter(Column("a") == 1)
                try XCTAssertNil(request.selectionInfo(db).rowIds)
            }
            do {
                let request = Record.filter(Column("id") >= 1)
                try XCTAssertNil(request.selectionInfo(db).rowIds)
            }
            
            do {
                let request = Record.filter((Column("id") == 1) || (Column("a") == "foo"))
                try XCTAssertNil(request.selectionInfo(db).rowIds)
            }

            // No rowId
            
            do {
                let request = Record.filter(Column("id") == nil)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [])
            }

            do {
                let request = Record.filter(Column("id") === nil)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [])
            }
            
            do {
                let request = Record.filter(nil == Column("id"))
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [])
            }
            
            do {
                let request = Record.filter(nil === Column("id"))
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [])
            }
            
            do {
                let request = Record.filter((Column("id") == 1) && (Column("id") == 2))
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [])
            }
            do {
                let request = Record.filter(key: 1).filter(key: 2)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [])
            }

            // Single rowId
            
            do {
                let request = Record.filter(Column("id") == 1)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(Column("id") === 1)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(Column("id") == 1 && Column("a") == "foo")
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(Column.rowID == 1)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(1 == Column("id"))
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(1 === Column("id"))
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(1 === Column.rowID)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(key: 1)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(key: 1).filter(key: 1)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }
            do {
                let request = Record.filter(key: 1).filter(Column("a") == "foo")
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1])
            }

            // Multiple rowIds
            
            do {
                let request = Record.filter(Column("id") == 1 || Column.rowID == 2)
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1, 2])
            }
            do {
                let request = Record.filter([1, 2, 3].contains(Column("id")))
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1, 2, 3])
            }
            do {
                let request = Record.filter([1, 2, 3].contains(Column.rowID))
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1, 2, 3])
            }
            do {
                let request = Record.filter(keys: [1, 2, 3])
                try XCTAssertEqual(request.selectionInfo(db).rowIds!, [1, 2, 3])
            }
        }
    }
    
    func testUpdateStatement() throws {
        let dbQueue = try makeDatabaseQueue()
        try dbQueue.inDatabase { db in
            try db.execute("CREATE TABLE foo (id INTEGER, bar TEXT, baz TEXT, qux TEXT)")
            let statement = try db.makeUpdateStatement("UPDATE foo SET bar = 'bar', baz = 'baz' WHERE id = 1")
            XCTAssertFalse(statement.invalidatesDatabaseSchemaCache)
            XCTAssertEqual(statement.databaseEventKinds.count, 1)
            guard case .update(let tableName, let columnNames) = statement.databaseEventKinds[0] else {
                XCTFail()
                return
            }
            XCTAssertEqual(tableName, "foo")
            XCTAssertEqual(columnNames, Set(["bar", "baz"]))
        }
    }
    
    func testRowIdNameInUpdateStatement() throws {
        // Here we test that sqlite authorizer gives the "ROWID" name to
        // the rowid column, regardless of its name in the request (rowid, oid, _rowid_)
        //
        // See also testRowIdNameInSelectStatement
        
        guard sqlite3_libversion_number() > 3007013 else {
            // This test fails on iOS 8.1 (SQLite 3.7.13)
            // TODO: evaluate the consequences
            return
        }
        let dbQueue = try makeDatabaseQueue()
        try dbQueue.inDatabase { db in
            try db.execute("CREATE TABLE foo (name TEXT)")
            do {
                let statement = try db.makeUpdateStatement("UPDATE foo SET rowid = 1")
                XCTAssertEqual(statement.databaseEventKinds.count, 1)
                guard case .update(let tableName, let columnNames) = statement.databaseEventKinds[0] else {
                    XCTFail()
                    return
                }
                XCTAssertEqual(tableName, "foo")
                XCTAssertEqual(columnNames, ["ROWID"])
            }
            do {
{'fraction_non_alphanumeric': 0.11072212662433988, 'fraction_numerical': 0.007832433394647837, 'mean_word_length': 1.6301498127340823, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1454052', 'n_tokens_mistral': 4681, 'n_tokens_neox': 4389, 'n_words': 1007}