35. Example: Pseudocode # Open connection c1 = open('foods.db') # Compile a statement stmt = c1.prepare('SELECT * FROM episodes') # Execute and iterate over results while stmt.step() print stmt.column('name') end # Finalize statement stmt.finalize() c1.close()
36. Example: C #include <sqlite3.h> int main(int argc, char **argv) { int rc, i, ncols; sqlite3 *cnx; sqlite3_stmt *stmt; char *sql; const char *tail; /* Connect to database*/ sqlite3_open("db", &cnx); /* Prepare statement */ sql = "SELECT * FROM x"; sqlite3_prepare(cnx, sql, (int)strlen(sql), &stmt, &tail); /* Get the number of columns in statement */ ncols = sqlite3_column_count(stmt);
37. A Simple Example: C (cont.) /* Iterate over result set. */ while(sqlite3_step(stmt) == SQLITE_ROW) { for(i=0; i < ncols; i++) { fprintf(stderr, "'%s' ", sqlite3_column_text(stmt, i)); } } /* Finalize */ sqlite3_finalize(stmt); /* Close database */ sqlite3_close(cnx); return 0; }
38.
39.
40. Data Structures, Locks, and Storage c1 = open('foods.db') c2 = open('foods.db') stmt1 = c1.prepare('SELECT * FROM episodes') stmt2 = c1.prepare('SELECT * FROM episodes') stmt3 = c2.prepare('INSERT INTO episodes...') stmt4 = c2.prepare('UPDATE episodes ...') while stmt1.step() print stmt1.column('name') stmt4.step() end ...
41.
42.
43.
44.
45.
46.
47. Query Processing: Round 3 /* Stripped down: */ /* The gist of executing a query. */ sqlite3_open("db", &cnx); sqlite3_prepare(cnx, SQL, sqllen, &stmt, NULL); while(sqlite3_step(stmt) == SQLITE_ROW) { /* Do something with row. */ } sqlite3_finalize(stmt);
82. This Won't Work c1 = open('foods.db') c2 = open('foods.db') stmt = c1.prepare('SELECT * FROM episodes') while stmt.step() c2.exec('UPDATE episodes SET …) end stmt.finalize() c1.close() c2.close()
83.
84. Solution: Single Connection c1 = open('foods.db') stmt = c1.prepare('SELECT * FROM episodes') while stmt.step() sql = 'UPDATE episodes SET …' c1.exec(sql) end stmt.finalize() c1.exec('COMMIT') c1.close()
85.
86. Brute Force stmt = c1.prepare('SELECT * FROM episodes') while stmt.step() sql = 'UPDATE episodes SET …' while c1.exec(sql) != SQLITE_OK # Keep trying until it works end end
87. Actual Example #!/usr/bin/env lua require "sqlite3" db = sqlite3.new() stmt = sqlite3_stmt.new() -- Connect to database sqlite3.open(db, "foods.db") -- Start a transaction if sqlite3.exec(db, "BEGIN") ~= SQLITE_OK then print('BEGIN FAILED: ' .. sqlite3.errmsg(db)) return false end -- Compile a SELECT statement sql = 'SELECT id, type_id, name FROM foods ORDER BY id LIMIT 1' sqlite3.prepare(db, sql, stmt); -- Execute it. This is where an EXCLUSIVE lock will stop us local rc = sqlite3.step(stmt) -- Check the value. If not SQLITE_ROW, we have a problem. if rc ~= SQLITE_ROW then print("SELECT FAILED: " .. sqlite3.errmsg(db)) os.exit(1) end
88. -- Iterate over result set while rc == SQLITE_ROW do -- Get the record id local id = sqlite3.column_int(stmt, 0) print("Fetched row: id="..id) -- Update the row. Keep trying until it goes through sql = 'UPDATE foods SET type_id = 100 WHERE id=' .. id while sqlite3.exec(db, sql) ~= SQLITE_OK do print('UPDATE FAILED: ' .. sqlite3.errmsg(db)) os.execute("sleep 1") end -- Next row rc = sqlite3.step(stmt) end -- Finalize sqlite3.finalize(stmt); -- Commit transaction if sqlite3.exec(db, "COMMIT") ~= SQLITE_OK then print('COMMIT FAILED: ' .. sqlite3.errmsg(db)) return false end sqlite3.close(db)
89.
90.
91.
92.
93. Suggested Approach c1 = open('foods.db') while c1.exec('BEGIN IMMEDIATE') != SQLITE_SUCCESS end stmt = c1.prepare('SELECT * FROM episodes') while stmt.step() # Will always work because we're in RESERVED c1.exec('UPDATE episodes SET …) end stmt.finalize() c1.exec('COMMIT') c1.close()
94.
95.
96.
97. Pop Quiz # The correct place to apply brute force. while c1.exec('BEGIN IMMEDIATE') != SQLITE_OK end sql = 'UPDATE ...' stmt = c1.prepare(sql) while stmt.step() != SQLITE_DONE # Keep trying end stmt.finalize() c1.exec('COMMIT')
98.
99. Example select_sql = 'SELECT * from foods where type_id > 0' ORDER BY type_id; update_sql = 'UPDATE foods set type_id=type_id+1 where' stmt = c1.prepare('SELECT * FROM episodes') while stmt.step() id = sqlite3_column_int(stmt, 0) c1.exec(update_sql + 'id=' + id) end
100.
101. Actual Example #!/usr/bin/env lua require "sqlite3" [==[ Assumes the following in database: CREATE TABLE discounts ( product_id INTEGER PRIMARY KEY value INT ); INSERT INTO discounts (value) VALUES (1); ]==] function print_value(db) local sql = "SELECT value FROM discounts" local stmt = sqlite3_stmt.new() local rc = sqlite3.prepare(db, sql, stmt); if rc ~= SQLITE_OK then error(sqlite3.errmsg(db)) end sqlite3.step(stmt) print(string.format( "RESULT: value = %i", sqlite3.column_int(stmt, 0))) sqlite3.finalize(stmt); end
102. -- Connect to database db = sqlite3.new() stmt = sqlite3_stmt.new() sqlite3.open(db, "test.db") -- Drop/recreat discounts table, if exists clear_table(db) -- Create an index on the discount column sqlite3.exec(db, "CREATE INDEX discounts_value_idx ON discounts(value)") sql = "SELECT * FROM discounts WHERE value > 0" rc = sqlite3.prepare(db, sql, stmt); if rc ~= SQLITE_OK then print('SQL ERROR: ' .. sqlite3.errmsg(db)) print(rc) os.exit(1) end -- Iterate through result set while sqlite3.step(stmt) == SQLITE_ROW do local id = sqlite3.column_int(stmt, 0) local type_id = sqlite3.column_int(stmt, 1) print(string.format("SQLITE_ROW: id=%-2i x=%-2i", id, type_id)) -- Increment value by 1 sqlite3.exec( db, "UPDATE discounts SET value=value+1 " .. " WHERE product_id=" .. id ) end
103. -- Close statement handle sqlite3.finalize(stmt); -- Print the current value print_value(db) -- Close database sqlite3.close(db)
104.
105.
106.
107.
108.
109. Example c1 = open('foods.db') c2 = open('foods.db') c2.exec('CREATE TEMPORARY TABLE temp_epsidodes AS SELECT * from episodes') stmt = c1.prepare('SELECT * FROM episodes') while stmt.step() print stmt.column('name') c2.exec('UPDATE temp_episodes SET …') end stmt.finalize()
110. c2.exec('BEGIN IMMEDIATE') # Use conflict resolution to do the update in # in a single step c2.exec('REPLACE INTO episodes SELECT * FROM temp_episodes') c2.exec('COMMIT') c1.close() c2.close()
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121. Page Cache 101: Cache Sizing *** Table FOODS w/o any indices ************************************** Percentage of total database.......... 27.5% Number of entries..................... 412 Bytes of storage consumed............. 11264 Bytes of payload...................... 7245 64.3% Average payload per entry............. 17.58 Average unused bytes per entry........ 4.67 Average fanout........................ 10.00 Fragmentation......................... 60.0% Maximum payload per entry............. 49 Entries that use overflow............. 0 0.0% Index pages used...................... 1 Primary pages used.................... 10 Overflow pages used................... 0 Total pages used...................... 11 Unused bytes on index pages........... 942 92.0% Unused bytes on primary pages......... 982 9.6% Unused bytes on overflow pages........ 0 Unused bytes on all pages............. 1924 17.1%