obsidian/wiki/concepts/sqlite-not-null-as-boolean.md
2026-05-05 21:04:37 +01:00

58 lines
2.1 KiB
Markdown

---
title: "SQLite: IS NOT NULL AS Boolean"
aliases: [sqlite-not-null-boolean, sqlite-derived-boolean]
tags: [sqlite, sql, security, pattern]
sources: [sandbox]
created: 2026-05-05
updated: 2026-05-05
---
# SQLite: IS NOT NULL AS Boolean
When a column contains sensitive data (e.g. a password hash), never select it directly to answer a yes/no question. Use `(column IS NOT NULL) AS flag` to return a derived boolean instead.
## Key Takeaways
- `(password_hash IS NOT NULL) AS has_password` → returns `1` or `0`, never the hash
- Hash never leaves the database layer — client gets the correct boolean
- Standard pattern for any column that must stay server-side
## Pattern
```sql
-- BAD: leaks the hash to the application layer
SELECT id, email, password_hash FROM users WHERE id = ?;
-- GOOD: returns a boolean, hash stays in DB
SELECT id, email, (password_hash IS NOT NULL) AS has_password FROM users WHERE id = ?;
```
In SQLite, the expression evaluates to `1` (true) or `0` (false). Map to a JS/Python boolean at the application layer:
```js
// Node.js / better-sqlite3
const user = db.prepare(`
SELECT id, email, (password_hash IS NOT NULL) AS has_password
FROM users WHERE id = ?
`).get(userId);
// SQLite returns 1/0; coerce to boolean
user.hasPassword = Boolean(user.has_password);
```
## Bug This Fixes
The `userPublic()` helper was selecting `u.password_hash` directly. The result object included the raw hash — or, worse, `undefined` when the column was NULL — causing `hasPassword` to always evaluate to `false` (because the hash value was truthy but the field name wasn't mapped correctly).
Fix: replace the direct column with `(password_hash IS NOT NULL) AS has_password`.
## Generalisation
The same pattern applies to any secret or large binary:
- `(api_key IS NOT NULL) AS has_api_key`
- `(avatar_blob IS NOT NULL) AS has_avatar`
- `(refresh_token IS NOT NULL) AS is_linked`
## Related
- [[wiki/concepts/fastapi-response-model-silent-field-strip|fastapi-response-model-silent-field-strip]] — similar idea: strip sensitive fields at the serialization layer