Parameterized Queries
Whenever an external value (user input, program variable) needs to appear in a
query, use positional parameters instead of string concatenation. Each ? in
the SQL is replaced, in order, by the corresponding element of the bindings array
passed as the second argument to execute or query.
This has two benefits: it protects against SQL injection and lets the driver reuse the query's execution plan across repeated calls.
Inserts users with ? and filters by minimum age — the values never touch the
SQL text.
04-parameterized.zolo
// Feature: Database — parameterized queries (`?` + bindings array)
// Syntax: `db.query(sql, [v1, v2, ...])` and `db.execute(sql, [...])`
// When to use: ALWAYS when SQL receives external values. Prevents SQL
// injection and lets the driver cache the query plan.
use std::Database
let db = Database.open("sqlite://:memory:").unwrap()
defer db.close()
db.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)").unwrap()
// `?` in order; the bind array fills it in.
db.execute("INSERT INTO users (id, name, age) VALUES (?, ?, ?)", [1, "Ana", 30]).unwrap()
db.execute("INSERT INTO users (id, name, age) VALUES (?, ?, ?)", [2, "Bruno", 25]).unwrap()
db.execute("INSERT INTO users (id, name, age) VALUES (?, ?, ?)", [3, "Carla", 40]).unwrap()
const min_age = 28
let rows = db.query("SELECT name, age FROM users WHERE age >= ? ORDER BY age", [min_age]).unwrap()
print("users aged {min_age}+:")
for row in rows {
print(" {row.name} ({row.age})")
}
// expected:
// users aged 28+:
// Ana (30)
// Carla (40)
Requires the Zolo CLI/host — open in the playground or run locally.
Challenge
Add a fourth user via parameters and filter by name using
WHERE name = ?. What happens if you pass nil as a value?