Skip to content

now() in INSERT/UPSERT VALUES stores literal string "now()" instead of evaluating — TIMESTAMP columns end up as epoch 0 #33

@hollanf

Description

@hollanf

Summary

now() in the VALUES (...) list of INSERT / UPSERT is not evaluated. It is stored as the literal string "now()", which then surfaces as 1970-01-01T00:00:00.000000Z (epoch 0) when the target column is TIMESTAMP in a TYPE DOCUMENT STRICT collection. No error is raised.

Environment

  • NodeDB v0.0.2, nodedb-0.0.2-linux-arm64 release binary
  • HTTP endpoint http://localhost:6480/query

Reproduction

curl -s -X POST http://localhost:6480/query -H "Content-Type: application/json" \
  -d '{"sql":"CREATE COLLECTION upsert_now_test TYPE DOCUMENT STRICT (id STRING PRIMARY KEY, t TIMESTAMP)"}'

curl -s -X POST http://localhost:6480/query -H "Content-Type: application/json" \
  -d "{\"sql\":\"UPSERT INTO upsert_now_test (id, t) VALUES ('t1', now())\"}"

curl -s -X POST http://localhost:6480/query -H "Content-Type: application/json" \
  -d "{\"sql\":\"INSERT INTO upsert_now_test (id, t) VALUES ('t2', now())\"}"

curl -s -X POST http://localhost:6480/query -H "Content-Type: application/json" \
  -d '{"sql":"SELECT id, t FROM upsert_now_test"}'

Expected

t is the wall-clock time at DML evaluation.

Actual

[
  {"data": {"id": "t1", "t": "1970-01-01T00:00:00.000000Z"}},
  {"data": {"id": "t2", "t": "1970-01-01T00:00:00.000000Z"}}
]

Both the UPSERT and INSERT paths hit this. The statement is tagged as success (tag: "UPSERT" / tag: "INSERT"); no error raised.

Source pointers

  • nodedb-sql/src/planner/dml.rs:474-475expr_to_sql_value() falls through unknown function calls to Ok(SqlValue::String(format!("{expr}"))). The inline comment reads: "Other functions like now() — store as string for runtime eval." The runtime eval path doesn't exist on the DML write side.
  • nodedb/src/control/planner/sql_plan_convert/dml.rs:37-45 — the DOCUMENT STRICT write path does not invoke any scalar-function evaluator on the incoming values before msgpack encoding.
  • nodedb/src/control/planner/.../defaults.rs:21evaluate_default_expr() does handle NOW() correctly, but is only called for schema-defined DEFAULT values, not for user-supplied VALUES expressions.

Workaround

Compute ISO timestamp application-side and pass as a string literal:

UPSERT INTO foo (id, t) VALUES ('x', '2026-04-16T00:40:12.209Z');

Test coverage gap

No tests in the repo cover INSERT ... VALUES (col, now()) asserting a non-zero timestamp — only DEFAULT now() schema paths are exercised.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions