Skip to content

[FlightSQL][JDBC] NullPointerException in DatabaseMetadata methods when SqlInfo is unavailable #994

Description

@merzbird

Describe the bug

Multiple DatabaseMetadata methods in the Arrow Flight SQL JDBC driver throw NullPointerException when the server doesn't provide certain SqlInfo values. The ArrowDatabaseMetadata.getSqlInfoAndCacheIfCacheIsEmpty() method returns null, but calling code doesn't handle null defensively before invoking methods like .intValue(), .booleanValue(), or .isEmpty().

Affected Methods

All 68+ DatabaseMetadata methods that rely on getSqlInfoAndCacheIfCacheIsEmpty() are affected, including:

Integer-returning methods (20 methods)

  • getMaxBinaryLiteralLength()
  • getMaxCharLiteralLength()
  • getMaxColumnNameLength()
  • getMaxColumnsInGroupBy()
  • getMaxColumnsInIndex()
  • getMaxColumnsInOrderBy()
  • getMaxColumnsInSelect()
  • getMaxColumnsInTable()
  • getMaxConnections()
  • getMaxCursorNameLength()
  • getMaxIndexLength()
  • getMaxSchemaNameLength()
  • getMaxProcedureNameLength()
  • getMaxCatalogNameLength()
  • getMaxRowSize()
  • getMaxStatementLength()
  • getMaxStatements()
  • getMaxTableNameLength()
  • getMaxTablesInSelect()
  • getMaxUserNameLength()

Boolean-returning methods (30 methods)

  • supportsColumnAliasing()
  • nullPlusNonNullIsNull()
  • supportsTableCorrelationNames()
  • supportsDifferentTableCorrelationNames()
  • supportsExpressionsInOrderBy()
  • supportsOrderByUnrelated()
  • supportsLikeEscapeClause()
  • supportsNonNullableColumns()
  • supportsIntegrityEnhancementFacility()
  • isCatalogAtStart()
  • supportsSelectForUpdate()
  • supportsStoredProcedures()
  • supportsCorrelatedSubqueries()
  • doesMaxRowSizeIncludeBlobs()
  • supportsTransactions()
  • dataDefinitionCausesTransactionCommit()
  • dataDefinitionIgnoredInTransactions()
  • supportsBatchUpdates()
  • supportsSavepoints()
  • supportsNamedParameters()
  • locatorsUpdateCopy()
  • supportsStoredFunctionsUsingCallSyntax()

Support level methods (18 methods)

  • getDefaultTransactionIsolation()
  • supportsGroupBy()
  • supportsGroupByUnrelated()
  • supportsMinimumSQLGrammar()
  • supportsCoreSQLGrammar()
  • supportsExtendedSQLGrammar()
  • supportsANSI92EntryLevelSQL()
  • supportsANSI92IntermediateSQL()
  • supportsANSI92FullSQL()
  • supportsOuterJoins()
  • supportsFullOuterJoins()
  • supportsLimitedOuterJoins()
  • supportsSchemasInProcedureCalls()
  • supportsSchemasInIndexDefinitions()
  • supportsSchemasInPrivilegeDefinitions()
  • supportsCatalogsInIndexDefinitions()
  • supportsCatalogsInPrivilegeDefinitions()
  • supportsPositionedDelete()
  • supportsPositionedUpdate()
  • supportsSubqueriesInComparisons()
  • supportsSubqueriesInExists()
  • supportsSubqueriesInIns()
  • supportsSubqueriesInQuantifieds()
  • supportsUnion()
  • supportsUnionAll()

Map-returning methods

  • supportsConvert()

Component(s)

  • FlightSQL
  • JDBC

To Reproduce

importjava.sql.*;
importjava.util.Properties;
publicclassDatabaseMetadataTest {
publicstaticvoidmain(String[] args) throwsSQLException {
Stringurl = "jdbc:arrow-flight-sql://...";
Propertiesprops = newProperties();
Driverdriver = DriverManager.getDriver(url);
try (Connectionconn = driver.connect(url, props)) {
DatabaseMetaDatametaData = conn.getMetaData();
// All of these throw NullPointerExceptionSystem.out.println(metaData.getMaxBinaryLiteralLength());
System.out.println(metaData.supportsTransactions());
System.out.println(metaData.supportsGroupBy());
}
}
}

Error Output

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Long.intValue()"
because the return value of "org.apache.arrow.driver.jdbc.ArrowDatabaseMetadata.getSqlInfoAndCacheIfCacheIsEmpty
(org.apache.arrow.driver.jdbc.shaded.org.apache.arrow.flight.sql.impl.FlightSql$SqlInfo, java.lang.Class)" is null
at org.apache.arrow.driver.jdbc.ArrowDatabaseMetadata.getMaxBinaryLiteralLength(ArrowDatabaseMetadata.java:xxx)

Expected behavior

  1. Option A: Return sensible defaults when SqlInfo is unavailable:

    • Integer methods: return 0 (as per JDBC spec for "no limit" or "unknown")
    • Boolean methods: return false (conservative/safe default)
    • Support level methods: return appropriate default enums
    • Map methods: return empty map
  2. Option B: Throw SQLException with a descriptive message indicating the server doesn't support the requested SqlInfo

  3. Methods should NOT throw unchecked NullPointerException - this violates JDBC contracts and the principle of least surprise

Environment

Arrow Version:

  • 18.3.0

Java Version:

  • Java 11+

OS:

  • All platforms

JDBC Specification Reference

Per JDBC 4.3 specification:

  • Methods returning int should return 0 when the limit is unknown or there is no limit
  • Methods returning boolean should return false for unsupported features
  • Methods should throw SQLException for errors, not unchecked exceptions

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type: bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions