Skip to content

refactor(jdbc): migrate Read Path to BigQueryTypeRegistry - #14063

Open
Neenu1995 wants to merge 11 commits into
jdbc-phase4-registry-integrationfrom
jdbc-phase4-registry-read-path
Open

refactor(jdbc): migrate Read Path to BigQueryTypeRegistry#14063
Neenu1995 wants to merge 11 commits into
jdbc-phase4-registry-integrationfrom
jdbc-phase4-registry-read-path

Conversation

@Neenu1995

@Neenu1995 Neenu1995 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

This PR migrates the BigQuery JDBC read-path implementations (Arrow and Json) to utilize the newly introduced BigQueryTypeRegistry for unified type lookups and high-performance coercion.

Also made the following fixes in implementation and tests:

Type Registry Consolidation & Read-Path Migration

  • Unified Coercion: Replaced the legacy BigQueryTypeCoercer with BigQueryTypeRegistry as the single source of truth for all type casting and format mapping.
  • Result Set Integration: Refactored BigQueryBaseResultSet, BigQueryArrowResultSet, and BigQueryJsonResultSet (along with their nested Struct and Array counterparts) to funnel all getObject() and primitive getter calls through the registry.

Temporal Type & JDBC 4.2 Spec Compliance

  • Strict UTC Anchoring: Anchored java.sql.Date to strictly format at UTC midnight, and java.sql.Time to 1970-01-01 in the local JVM, ensuring correct String serialization and civil time preservation.
  • Illegal Coercion Blocking: Added explicit guards to throw BigQueryJdbcException for invalid cross-temporal conversions (e.g., blocking java.sql.Date -> java.sql.Time and java.sql.Time -> java.sql.Date), preserving backward compatibility with legacy strictness.
  • Formatter Optimization: Extracted DateTimeFormatter compilations into static final constants to guarantee fast-path string serialization for TIMESTAMP (6 decimal precision) and TIME (3 decimal precision) without per-row object allocation penalties.

Complex Types & Boundary Protection

  • Arrow Primitives: Handled raw Arrow Integer (days since epoch) and Long (microseconds since epoch) unboxing explicitly inside Arrow structures to bypass global registry mutations, fixing nested RANGE and ARRAY rendering.
  • Strict Bounds Checking: Implemented explicit overflow/underflow protections (MAX_VALUE / MIN_VALUE guards) when coercing BigDecimal and Long values down to smaller primitives (Integer, Short, Byte) to prevent silent data corruption.

@Neenu1995
Neenu1995 requested review from a team as code owners August 13, 2026 01:15

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request refactors type conversion and mapping across the BigQuery JDBC driver by replacing BigQueryTypeCoercer and BigQueryJdbcTypeMappings with BigQueryTypeRegistry. This change requires several methods to declare throwing SQLException. The review feedback suggests keeping the parameter type as FieldValue in BigQueryJsonStruct to avoid redundant downcasts, catching Exception instead of RuntimeException in BigQueryBaseResultSet to properly handle SQLException during conversion, and removing redundant blank lines in BigQueryTypeRegistry.

Arrays.asList(String.class),
(val, targetClass, zone) -> String.valueOf(val));
(val, targetClass, zone) -> {
if (val == null) return null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

please update with brackets instead of a single line if-return

@@ -154,9 +207,16 @@ static TypeDescriptor<?> createDateDescriptor() {
// TODO(Phase 3): Add native JSR-310 fast-path to bypass boxing for LocalDate
Date sqlDate;
if (val instanceof Date) sqlDate = (Date) val;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please add {}

@@ -154,9 +207,16 @@ static TypeDescriptor<?> createDateDescriptor() {
// TODO(Phase 3): Add native JSR-310 fast-path to bypass boxing for LocalDate
Date sqlDate;
if (val instanceof Date) sqlDate = (Date) val;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please add {}

Object getCoercedValue(int index) throws SQLException {
LOG.finestTrace("getCoercedValue");
Object value = this.values.get(index);
if (value instanceof Integer

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can this be moved to TypeRegistry too? We should avoid conversions outside of it

public static Timestamp boxTimestamp(String val) {
// Check if the value is a numeric float string (e.g. "1680174859.8202269" from JSON API)
try {
if (val.indexOf('-') < 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we need this if check? There are a lot of other cases when it won't be a valid float number string. We can just validate the format or allow BigDecimal(val) to fail parsing

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.

2 participants