swiftsqlite

Swift SQLite3 Not updating, but cannot get the exact error


I had this code working at one time but all of a sudden, it's not working anymore.

I'm creating a table with the following:

// Create Stock Table
func createStockTable() {
    let createTableString = """
    CREATE TABLE IF NOT EXISTS Stocks (
        id INTEGER PRIMARY KEY,
        stockName STRING,
        status INT,
        imgName STRING,
        prevClose DOUBLE,
        curPrice DOUBLE,
        yield DOUBLE,
        noShares INT, 
        capitalization DOUBLE,
        lastUpdated String
    );
    """
    var createTableStatement: OpaquePointer? = nil
    if sqlite3_prepare_v2(db, createTableString, -1, &createTableStatement, nil) == SQLITE_OK {
        if sqlite3_step(createTableStatement) == SQLITE_DONE {
            print("Stock table is created successfully")
        } else {
            print("Stock table creation failed.")
        }
        sqlite3_finalize(createTableStatement)
    }
}

This is working just fine.

I have the following insert function to insert the rows:

// add entries to Stock table
func insertStocks(id: Int, stockName: String, status: Int, imgName: String, prevClose: Double, curPrice: Double, yield: Double, noShares: Int, capitalization: Double, lastUpdated: String) -> Bool {
    let stocks = getAllStocks()
    for stock in stocks {
        if stock.id == id {
            return false
        }
    }
    let insertStatementString = "INSERT INTO Stocks (id, stockName, status, imgName, prevClose, curPrice, yield, noShares, capitalization, lastUpdated) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"
    var insertStatement: OpaquePointer? = nil
    if sqlite3_prepare_v2(db, insertStatementString, -1, &insertStatement, nil) == SQLITE_OK {
        sqlite3_bind_int(insertStatement,1,Int32(id))
        sqlite3_bind_text(insertStatement, 2, (stockName as NSString).utf8String, -1, nil)
        sqlite3_bind_int(insertStatement, 3, Int32(status))
        sqlite3_bind_text(insertStatement, 4, (imgName as NSString).utf8String, -1, nil)
        sqlite3_bind_double(insertStatement, 5, Double(prevClose))
        sqlite3_bind_double(insertStatement, 6, Double(curPrice))
        sqlite3_bind_double(insertStatement, 7, Double(yield))
        sqlite3_bind_int64(insertStatement,8, Int64(noShares))
        sqlite3_bind_double(insertStatement, 9, Double(capitalization))
        sqlite3_bind_text(insertStatement, 10, (lastUpdated as NSString).utf8String, -1, nil)
        if sqlite3_step(insertStatement) == SQLITE_DONE {
            print("Stock Entry was created successfully")
            sqlite3_finalize(insertStatement)
            return true
        } else {
            print("Stock Entry Insert failed")
            return false
        }
    } else {
        print("INSERT Statement has failed")
        return false
    }
}

When I run the following, it gives me an error that the stock entry insert failed. I cannot seem to determine why.

func addStocks() {
    db.insertStocks(id: 1, stockName: "Tulsa Motors", status: 1, imgName: "Tulsa_logo", prevClose: 125.18, curPrice: 125.18, yield: 0.025, noShares: 14357698, capitalization: myFunc.calcMarketCap(curPrice: 128.18, noShares: 14357698), lastUpdated: "2025-05-01 17:00:00")
}

[edit] Tim has raised the question on the creation of the db object, so I'm posting that code as well:

let dataPath: String = "MyDB"
    let functions = Functions()
    var db: OpaquePointer?
    
    // Create DB
    func openDatabase()->OpaquePointer?{
        let filePath = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent(dataPath)
        
        var db: OpaquePointer? = nil
        if sqlite3_open(filePath.path, &db) != SQLITE_OK{
            debugPrint("Cannot open DB.")
            return nil
        }
        else{
            print("DB successfully created.")
            return db
        }
    }

The only issue I can possibly see is the INT32 and INT64 but those worked before so I'm not sure why that would no longer be working.

Suggestions?


Solution

  • The problem is with the primary key, when you include a column with the type INTEGER PRIMARY KEY this automatically becomes an alias for a built in type called ROWID.

    This type has an auto increment functionality built in and will generate a new unique id (primary key) every time you do an insert. So the problem here is that you should not include the id property and a value for it in your insert code since SQLite will handle it for you.

    So change the insert statement to

    let insertStatementString = "INSERT INTO Stocks (stockName, status, imgName, prevClose, curPrice, yield, noShares, capitalization, lastUpdated) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);"
    

    and remove the line

    sqlite3_bind_int(insertStatement,1,Int32(id))
    

    in your insertStocks method and then update the index column values for the following rows.