← All notes

Notes · 2026-08-28

A timestamp that stores NULL and says it worked, and a boolean note that went stale

ArcadeDB stores a space-separated timestamp with a fraction as NULL under a successful INSERT - the exact form psqlodbc binds. Filed by the project as a critical issue. And the NULL BOOLEAN note from August turned out to be fixed before we published it.

Two behaviours sat in this project's ArcadeDB compatibility notes since 2026-08-28, written down but never filed: a timestamp form that silently stored NULL, and a NULL BOOLEAN that read back as false. Both have now been settled, and in opposite directions. One turned out to be worse than the note said and is a critical issue in ArcadeDB's own tracker. The other had already been fixed before the note was ever published, which is the more useful lesson.

The timestamp: success, and no value

A DATETIME_MICROS property fed the string '2024-02-29 13:45:10.123456' stores NULL. The INSERT reports success. Nothing in the result says a value was dropped.

Either half of that literal on its own is fine:

literal='2024-02-29T13:45:10.123456'   stored=2024-02-29T13:45:10.123456
literal='2024-02-29 13:45:10.123456'   stored=>>> NULL <<<
literal='2024-02-29 13:45:10'          stored=2024-02-29T13:45:10

The T separator round-trips to the microsecond, and the space separator without a fraction round-trips too. Only the combination fails, and the combination is exactly what psqlodbc renders a bound SQL_TYPE_TIMESTAMP parameter as. So an application that binds a timestamp parameter — the ordinary thing to do — writes nothing and is told it wrote something.

ArcadeDB filed this themselves on 2026-09-21 as ArcadeData/arcadedb#8090, labelled severity:critical, after this project's notes were shared with them. Their issue names the cause, which our note could not: a blanket catch in Type.convert() logs the parse failure at FINE and returns null, and the insert carries on. It affects every PostgreSQL-wire client that binds a timestamp against a sub-second-precision property, not just this driver.

The literal is not the only way in. Binding the value as a parameter — the ordinary thing an application does, and the reason the form appears at all — loses it the same way, through psqlodbc and out the other side as Arrow:

INSERT INTO RetestT SET lbl = ?, ts = ?   with datetime(2024, 2, 29, 13, 45, 10, 123456)

DATETIME_MICROS column as Arrow:
   bound-param  -> None   <- value lost server-side

Confirmed on the same 26.9.1 image on 2026-09-21. The INSERT succeeds, SQLExecute returns SQL_SUCCESS, and the column is empty. Nothing between the application and the storage engine has a way to notice.

Until it is fixed, the way through is to write timestamps as ISO text with the T, which is what the compatibility entry for ArcadeDB says and what its parameter settings do.

The boolean: a note that aged badly

The second note said a NULL BOOLEAN had no NULL state over the wire: row 2's bo went in as NULL and read back as False, so the compatibility entry marks that column not_null.

That was observed on 2026-08-28 against arcadedata/arcadedb:latest, which was 26.8.1 at the time. It is not true any more, and it had already stopped being true before we wrote it up: a project contributor filed the same behaviour as #6674 on 2026-08-24 and closed it the same day, and the fix shipped in 26.9.1 on 2026-09-03.

A retest on 2026-09-21 against the official 26.9.1 image (arcadedata/arcadedb:26.9.1), through the route the compatibility entry actually describes — psqlodbc 16 with BoolsAsChar=0, then adbcBridge into Arrow:

BOOLEAN column as Arrow:
  schema: bool
   true-row    -> True
   false-row   -> False
   null-row    -> None   <- SQL NULL
   absent-row  -> None   <- SQL NULL

A NULL property and an absent property both arrive as SQL NULL, and true/false arrive intact. The behaviour is correct.

What that is worth saying out loud

A compatibility matrix is a set of claims with dates on them, and a claim about a fast-moving database is perishable. This one went stale in nine days, between the observation and the write-up, and the only reason it was caught is that the project read the note and pushed back on it rather than accepting it.

Two habits come out of that, and both are now in this project's routine. Every quirk carries the version it was seen on, so a reader can tell what a cell is actually about. And a quirk that is documented but not filed gets re-tested against the current release before it is repeated anywhere, because "documented, not reported" is exactly where a fixed bug goes to live on.

The ArcadeDB compatibility entry keeps its not_null flag for the boolean column for now, because the matrix row still records 26.9; it moves when the row is re-measured on 26.9.1.

Where these are tracked

Both rows are in this project's upstream record, and the ArcadeDB entry with its settings is on the ArcadeDB page.