Skip to content

Add --useTimestampMicros flag for microsecond precision without external schema - #1042

Open
keoliva wants to merge 3 commits into
spotify:masterfrom
keoliva:kaylao/timestamp-micros-support
Open

keoliva wants to merge 3 commits into
spotify:masterfrom
keoliva:kaylao/timestamp-micros-support

Conversation

@keoliva

@keoliva keoliva commented Aug 27, 2026

Copy link
Copy Markdown

Why

PostgreSQL stores TIMESTAMPTZ values at microsecond precision, but dbeam currently converts them through Timestamp.getTime(), truncating the sub-millisecond digits.

What

This adds --useTimestampMicros. When it is combined with --useAvroLogicalTypes, dbeam:

  • emits timestamp-micros in the schema generated from the JDBC ResultSet; and
  • converts JDBC timestamps using Timestamp.getNanos() so the microsecond component is preserved.

Schema and data now come from the same ResultSet, so no external schema file is needed and field order remains aligned.

Without --useTimestampMicros, behavior is unchanged.

e2e results

before & after
Screenshot 2026-09-04 at 10 16 41 PM

Screenshot 2026-09-04 at 10 09 44 PM

@keoliva
keoliva marked this pull request as ready for review August 27, 2026 21:24
@codecov

codecov Bot commented Aug 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.47368% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.76%. Comparing base (f8a8dc6) to head (bbe5103).

Additional details and impacted files
@@             Coverage Diff              @@
##             master    #1042      +/-   ##
============================================
- Coverage     91.92%   91.76%   -0.16%     
- Complexity      283      289       +6     
============================================
  Files            27       27              
  Lines          1015     1044      +29     
  Branches         86       91       +5     
============================================
+ Hits            933      958      +25     
- Misses           54       56       +2     
- Partials         28       30       +2     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@keoliva
keoliva force-pushed the kaylao/timestamp-micros-support branch from f56d22d to 69071d3 Compare August 28, 2026 15:38
@keoliva
keoliva force-pushed the kaylao/timestamp-micros-support branch from 69071d3 to 4924085 Compare September 5, 2026 01:39
@keoliva keoliva changed the title Support timestamp-micros precision when explicit schema is provided Add --useTimestampMicros flag for microsecond precision without external schema Sep 5, 2026
@keoliva
keoliva force-pushed the kaylao/timestamp-micros-support branch from 4924085 to 7d0ebb3 Compare September 5, 2026 02:08
@keoliva

keoliva commented Sep 5, 2026

Copy link
Copy Markdown
Author

New approach: A simple boolean flag that controls both the auto-generated schema (timestamp-micros vs timestamp-millis) and the value conversion (getNanos() vs getTime()). No external schema file needed that has to be kept up-to-date and the fields ordered in a particular order, because schema and data both come from the JDBC ResultSet.

final List<String> preCommand,
final String arrayMode,
final Boolean nullableArrayItems,
final Boolean useTimestampMicros) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this just read the option with a default value of false?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you say ‘read the option,’ which object would we read it from? JdbcExportPipelineOptions comes to mind, but it isn’t available in this method.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant rather than providing an override; all callers should provide a value for this


private Schema createAvroSchemaForSingleField(
final ResultSet resultSet, final boolean useLogicalTypes,
final boolean useTimestampMicros) throws SQLException {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, shouldn't this be reading the default value of the opt instead of having an override?

@keoliva keoliva Sep 9, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated this one too. All callers now explicitly provide a value.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

…nal schema

Replaces the previous approach of reading timestamp-micros from an
explicit --avroSchemaFilePath schema. The old approach required
hand-maintained .avsc files whose field order had to exactly match the
Postgres column order — a brittle contract that caused production
failures when ALTER TABLE columns were placed in "logical" positions
in the schema instead of their actual Postgres ordinal positions
(Avro binary is positional, so any mismatch corrupts the data stream).

The new --useTimestampMicros flag is simpler and safer:
- Schema generation: emits timestamp-micros (not timestamp-millis) in
  the auto-generated Avro schema when --useAvroLogicalTypes is also set
- Value conversion: reads Timestamp.getNanos() to preserve microsecond
  precision instead of truncating via Timestamp.getTime()
- Field order is always correct because both schema and data come from
  the same JDBC ResultSet — no external schema file to keep in sync

Usage:
  --useAvroLogicalTypes --useTimestampMicros

This is fully backwards-compatible: without --useTimestampMicros, all
behavior is identical to before.

Co-Authored-By: Claude <noreply@anthropic.com>
@keoliva
keoliva force-pushed the kaylao/timestamp-micros-support branch from 7d0ebb3 to 7d68033 Compare September 8, 2026 20:02
Co-authored-by: OpenAI Codex <codex@openai.com>
case DATE:
case TIME:
case TIME_WITH_TIMEZONE:
if (useTimestampMicros) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useTimestampMicros without useAvroLogicalTypes produces micros values with no schema annotation. AFAIK data processing tools interpret Avro long without logical type annotation as millis, and this is an established convention in DBeam. Maybe we should not allow using useTimestampMicros without useAvroLogicalTypes?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah just throw IMO

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point 3ff3c9c

Co-authored-by: OpenAI Codex <codex@openai.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants