liveBook · Manning

Parameterized query

As explained in Build Financial Software with Generative AI (From Scratch)

A parameterized query is a database query whose SQL structure is separated from values supplied as parameters.

A parameterized query keeps SQL structure separate from the values supplied to it. Instead of inserting a filename or hash into an SQL string, write placeholders in the statement and pass the values separately. This is a secure-coding practice because string interpolation in SQL is identified as ripe for SQL injection. section 5.6

In an ACH-file upload workflow, the database insert has a fixed shape: add a file name and file hash to `ach_files`. The changing values are the uploaded file’s name and the MD5 hash calculated from its contents. The SQL uses `%s` placeholders, while `(file.filename, md5_hash)` supplies the corresponding values. section 5.6

Store uploaded-file metadata safely

After reading the uploaded file and computing its hash, open a database connection and execute an insert such as `INSERT INTO ach_files (file_name, file_hash) VALUES (%s, %s)` with the filename and hash passed as a value tuple. The f-string is used for the multiline SQL literal here, not to interpolate those values into SQL. section 5.6

Use the technique consistently in database helpers and tests:

  • Keep table-name construction separate from parameter passing; f-strings may construct SQL where necessary, but values should still use parameterized queries. section 5.4.1
  • Use parameterized queries even for internal tooling, rather than assuming internal inputs cannot be malicious. section 5.4.1
  • Pair database tests with setup and teardown that clear tables, so repeated runs do not leave records that invalidate assertions. section 5.4.1
Listing 5.24 Updated endpoint to upload ACH files
@router.post("", status_code=status.HTTP_201_CREATED)
async def create_file(file: UploadFile = File(...)):
    contents = await file.read()  #1
    md5_hash  = hashlib.md5(contents).hexdigest() #2
    with DbUtils.get_db_connection() as conn: #3
        conn.execute( #4
            f"""   #4
            INSERT INTO ach_files (file_name, file_hash)  #4
            VALUES (%s, %s)  #4
            """, (file.filename, md5_hash)  #4
        )  #4
    return None #4

The upload endpoint shows the complete path from file contents to hash calculation, database connection, placeholder-based insert, and successful response. section 5.6

How Build Financial Software with Generative AI (From Scratch) covers it

How deep it goes
Demonstrates a placeholder-based INSERT and contrasts it with interpolated SQL, without detailing database-driver internals.
Examples
Uses an `ach_files` INSERT with a filename and MD5 hash, plus cleanup-oriented database tests.
What it assumes
Assumes familiarity with Python, SQL inserts, FastAPI endpoints, and pytest fixtures.
What you can do after
Apply it via psycopg to insert uploaded-file metadata without interpolating values into SQL.
How it connects
Connects SQL injection, FastAPI file uploads, MD5 hashes, database connections, and unit tests.

Also explained in

Compare how 8 books explain parameterized query →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Build Financial Software with Generative AI (From Scratch). The section links point to the parts of the book it draws on.