Chapter 29 — Quiz
13 questions. Answers at the bottom.
Multiple choice
Q1. In psycopg2, you execute SQL through a: - A) Connection only - B) Cursor (obtained from a connection) - C) Pool only - D) Repository
Q2. The correct placeholder for a value in a psycopg2 query is:
- A) An f-string {value}
- B) %s, with the value passed separately
- C) ? always
- D) + str(value)
Q3. SQL injection happens when:
- A) You use %s placeholders
- B) User input is concatenated/formatted into the SQL string and executed
- C) You use a connection pool
- D) You commit too often
Q4. Parameterized queries prevent injection because: - A) They escape quotes manually - B) The value is sent separately and never interpreted as SQL - C) They disable user input - D) They run faster
Q5. cur.execute("... WHERE id = %s", (user_id,)) — the %s is:
- A) Python string formatting
- B) A query placeholder filled safely by the driver
- C) A comment
- D) A wildcard
Q6. To make two inserts atomic, you: - A) Run them in separate connections - B) Wrap them in one transaction (commit both or rollback both) - C) Use two cursors - D) Add an index
Q7. RETURNING order_id in an INSERT lets you:
- A) Roll back
- B) Get the generated id without a second query
- C) Parameterize the query
- D) Pool connections
Q8. Opening a new connection per web request at scale: - A) Is best practice - B) Can exhaust the server's connections; use a pool - C) Prevents injection - D) Is required
Q9. A UniqueViolation exception means:
- A) A bug in psycopg2
- B) A unique constraint did its job (e.g., duplicate email) — handle it
- C) A connection failure
- D) A deadlock
Q10. You should parameterize: - A) Only strings - B) Every value coming from outside hard-coded literals - C) Nothing - D) Only numbers
True/False
Q11. Using an f-string to insert a "safe-looking" value into SQL is fine. (True / False)
Q12. You can parameterize a table or column name with %s. (True / False)
Short answer
Q13. Explain why cur.execute("SELECT * FROM users WHERE name = '" + name + "'") is dangerous and how to fix it.
---
Answer key
Q1 — B. A cursor executes SQL and holds results.
Q2 — B. %s placeholder with values passed separately (not f-strings).
Q3 — B. Concatenating/formatting user input into executed SQL.
Q4 — B. The value travels separately and is never parsed as SQL.
Q5 — B. It's a driver placeholder, not Python % formatting.
Q6 — B. One transaction → both or neither (atomicity).
Q7 — B. Returns generated columns (e.g., the new id) inline.
Q8 — B. Exhausts connections; use a pool.
Q9 — B. A constraint working as intended; catch and handle it.
Q10 — B. Every external value (not just strings/numbers).
Q11 — False. f-strings/format into SQL = injection risk, "safe-looking" or not. Always parameterize.
Q12 — False. Parameters are for values. Identifiers (table/column names) need separate, careful handling (psycopg2.sql).
Q13. It builds SQL by concatenating name into the string, so a malicious name like '; DROP TABLE users; -- becomes executed SQL (SQL injection) — an attacker can read, modify, or destroy data. Fix it by parameterizing: cur.execute("SELECT * FROM users WHERE name = %s", (name,)), so the value is sent separately and can never be interpreted as SQL.
Scoring: 12–13 you integrate safely; 9–11 re-drill parameterization; below 9, redo Exercises B.