Problem
On the fetch path, FetchRecordsQuery::HydrateCurrentRow (src/queries.cc:299) skips a column instead of assigning it in two cases, leaving the member at its default-constructed value:
- NULL or BLOB:
if (col_type == SQLITE_NULL || col_type == SQLITE_BLOB) { continue; } (src/queries.cc:316)
- empty TEXT / DATETIME:
if (byte_count == 0) { continue; } (src/queries.cc:342 and :353)
So a SQL NULL, an empty TEXT, and (for a numeric column read as NULL) all resolve to the member's default, and none is distinguishable from a genuinely stored zero/empty value.
Historical note: this issue originally described FetchRecordsQuery::GetColumnValue returning L"" for both SQLITE_NULL and empty TEXT, plus if (content.empty()) continue; in a text-based Hydrate. PR #31 removed that wstring round-trip in favor of direct typed hydration. The new code does explicitly detect SQLITE_NULL via sqlite3_column_type, but deliberately preserves the same skip-and-leave-default behavior, so the limitation below still stands.
Impact
- A column that is SQL
NULL and one holding an empty string (or numeric 0) are indistinguishable after hydration.
- A NULL/empty value is silently dropped — the member keeps its default rather than reflecting what is actually stored.
This conflation also blocks a clean implementation of nullable fields (#2), which needs to distinguish "absent" from "empty/zero".
Suggested direction
Represent NULL distinctly from a present-but-empty/zero value, in coordination with the nullable-fields work in #2 (e.g. a nullable wrapper that hydration sets to "unset" on SQLITE_NULL). The raw SQLITE_NULL detection already exists in HydrateCurrentRow; what is missing is a typed representation to carry "absent" back to the caller.
Problem
On the fetch path,
FetchRecordsQuery::HydrateCurrentRow(src/queries.cc:299) skips a column instead of assigning it in two cases, leaving the member at its default-constructed value:if (col_type == SQLITE_NULL || col_type == SQLITE_BLOB) { continue; }(src/queries.cc:316)if (byte_count == 0) { continue; }(src/queries.cc:342and:353)So a SQL
NULL, an emptyTEXT, and (for a numeric column read as NULL) all resolve to the member's default, and none is distinguishable from a genuinely stored zero/empty value.Impact
NULLand one holding an empty string (or numeric0) are indistinguishable after hydration.This conflation also blocks a clean implementation of nullable fields (#2), which needs to distinguish "absent" from "empty/zero".
Suggested direction
Represent
NULLdistinctly from a present-but-empty/zero value, in coordination with the nullable-fields work in #2 (e.g. a nullable wrapper that hydration sets to "unset" onSQLITE_NULL). The rawSQLITE_NULLdetection already exists inHydrateCurrentRow; what is missing is a typed representation to carry "absent" back to the caller.