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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions