Repository navigation
Conversation
…aseline Add the Spark 3.5 governed Doris JDBC read baseline with generic fallback, physical schema validation, vended credential enforcement, and read-only catalog boundaries. Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
Apply the repository Spotless formatting required by the Spark connector CI. Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
…ersion tag Keep the default Spark connector CI from starting the Doris 3.x image while retaining the focused test for the explicit multi-version matrix. Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
…ptions Iterate Spark's case-insensitive catalog options explicitly and assert their normalized keys in the Doris property converter test. Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
Code Coverage Report
Files
|
…ract Expose a read-only Doris JDBC table, reject protected catalog and scan options, and validate parameterized logical types against physical signatures. Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
|
This PR introduces a governed, read-only JDBC baseline for Apache Doris. It reuses the existing BaseCatalog SELECT_TABLE authorization path. Required vended credentials and protected-option checks apply only to jdbc-doris, preserving other JDBC providers’ behavior. Type normalization, native tablet reads, writes, and Docker infrastructure changes are outside this PR. The session-scoped opt-in selects one integration mode for all jdbc-doris catalogs in a Spark application. I would welcome maintainer guidance on whether per-catalog selection is required for this contribution. |
Constrain Connector/J column metadata to the requested database and exact table, and cover cross-database and pattern matches in Doris integration tests. Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
| } catch (ClassNotFoundException | SQLException | RuntimeException e) { | ||
| if (e instanceof IllegalArgumentException | ||
| && e.getMessage() != null | ||
| && e.getMessage().startsWith("Doris schema mismatch")) { | ||
| throw (IllegalArgumentException) e; | ||
| } | ||
| throw new IllegalArgumentException( | ||
| "Doris physical schema validation failed for " + identifier); |
There was a problem hiding this comment.
Every non-mismatch failure is rethrown without its cause, so users can't tell what went wrong.
A missing driver on the classpath (the most likely setup error, since the docs ask users to provide Connector/J themselves), an unreachable FE, an authentication failure, a vended account without SHOW COLUMNS access, or an unsupported type from typeConverter.toSparkType all end up as the same Doris physical schema validation failed for <ident>. Because this path fails closed, that is the error users will see most often.
Could you:
- keep the cause:
new IllegalArgumentException("Doris physical schema validation failed for " + identifier, e). Connector/J messages don't include the password; - use a private exception subclass for schema mismatches instead of matching the
"Doris schema mismatch"message prefix; - add a unit test with a wrong driver class name that asserts
getCause()is aClassNotFoundException?
There was a problem hiding this comment.
Schema checks now run outside the metadata-access try/catch, removing message-prefix matching without adding an exception subclass. Physical-access failures report their stage and available safe SQLState/vendor code. I kept raw causes omitted because Spark 3.5.3’s connection factory can include the JDBC URL in an exception, while #13489 requires connection details to stay out of errors and logs.
Driver loading remains delegated to Spark during catalog initialization. The new regression test enters through GravitinoDorisCatalogSpark35.initialize() with a nonexistent driver class and asserts the directly propagated ClassNotFoundException, the missing class name, and the absence of the JDBC URL and URL/vended password sentinels throughout the printed exception stack. All three catalog unit tests pass.
Would you accept this exception boundary and redaction approach?
| /** Validates one authorized Doris table against FE and JDBC physical metadata. */ | ||
| final class DorisPhysicalSchemaValidator35 { | ||
|
|
||
| private static final Set<String> ORDINARY_TYPES = |
There was a problem hiding this comment.
ORDINARY_TYPES lists 17 types, but SparkJdbcDorisReadBaselineIT35 only creates INT and VARCHAR(64) columns.
validateColumns requires the FE SHOW COLUMNS signature and the JDBC getColumns signature to be equal. When the two report a type differently, the table is rejected as a schema mismatch and can't be read. I haven't verified these against Doris, but from the code a few look risky:
datetimewith scale 0: FE may printdatetime, while JDBCDECIMAL_DIGITS = 0becomesdatetime(0);boolean: over the MySQL protocol, JDBC may reportTINYINT;string/text: JDBC may report a sizedVARCHAR, while FE printsstring;float,double,char,dateanddecimalaren't exercised either.
Could you add a table to the IT with one column per ORDINARY_TYPES entry, both nullable and NOT NULL, and read the values back? Any type that doesn't match should be normalized in typeSignature or removed from ORDINARY_TYPES and the docs.
There was a problem hiding this comment.
The IT now covers all 16 current ORDINARY_TYPES spellings: 15 parameterized cases plus a dedicated SMALLINT comparison. Each spelling has NOT NULL and nullable columns, non-null values, and actual NULL values in the nullable column. Aliases may resolve to the same physical metadata type.
Plain DATETIME is normalized to precision 0, and DECIMALV3 uses the normalized DECIMAL signature. CHAR and FLOAT remain rejected and documented. The narrowly scoped SMALLINT compatibility rule retains Spark ShortType; its dedicated test compares generic and specialized reads of the same Doris table, including signed bounds, Java Short values, and nullability.
Local validation against Doris 3.0.6.2 passed all 22 IT cases. The affected schema-validator suite passed all 14 unit tests, with zero failures, errors, or skips.
Report safe physical-schema failure context and remove redundant driver loading. Validate Doris scalar aliases with focused tests and document the supported read boundary. Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
Reuse the table's JDBCOptions for physical schema validation and preserve existing catalog bypass options with case-insensitive application precedence. Add regression coverage for connection properties, protected options, read-only boundaries, and predicate pushdown. Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
…ility Accept the confirmed SMALLINT metadata representation while retaining ShortType scans. Cover every allowlisted type spelling and compare generic and specialized reads on the same Doris table, including boundary and null values. Clarify the scope of inherited JDBC capabilities. Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
Update optional-binding and catalog-selection comments, use imports in tests, and restore the documentation's original trailing blank line. Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
Verify missing-driver diagnostics through catalog initialization and assert that the full exception stack excludes connection details. Restore the JDBC Logger return type spelling to satisfy Spotless. Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
Reuse the existing single-column validator helper and combine safe JDBC option checks while retaining application-only forwarding, bypass defaults, and application precedence. Keep all 22 Doris integration tests unchanged. Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
Preserve native JDBC property spelling and application overrides. Redact first physical-schema load failures, reject database-target and automatic database-creation options, and document application logging requirements. Add public catalog regressions and retain the complete Doris integration coverage. Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
[#13489] feat(spark-connector): Add the governed Doris batch-read baseline
What changes were proposed in this pull request?
This pull request adds a governed Apache Doris batch-read baseline for the Gravitino Spark connector.
spark.sql.gravitino.enableDorisSupportopt-in for Spark 3.5 / Scala 2.12.spark.bypass.*catalog properties and ordinary Spark JDBC read options. Match application overrides ignoring key case while preserving native JDBC property spelling, such asconnectTimeoutandsslMode, when forwarding to the driver.spark.bypass.*properties, including the driver optionsdbnameandcreateDatabaseIfNotExist.SHOW COLUMNSmetadata and JDBC metadata, selecting only the requested database and exact table and checking column order, names, ordinary type signatures, and nullability.JDBCOptionsand dialect connection factory for physical schema validation, preserving the configured driver and connection properties, including SSL settings and connection timeouts.SMALLINTrepresentation difference only when FE and JDBC reportSMALLINT, the logical Spark type isShortType, and Spark JDBC metadata usesIntegerType. KeepShortTypescans through the existing JDBC table and converter, with all other schema checks retained.ClassNotFoundExceptioninitialization failures remain diagnosable.Column names/order, FE/JDBC signatures, and nullability remain validated.
CHARandFLOATare rejected because their Gravitino logical types differ from the types exposed by Spark JDBC.The existing Spark JDBC V2 delegate determines supported pushdowns and partitioned reads. Doris-specific optimizations and routing for aggregates, Top-N, limits, offsets, and partitioned reads, plus native tablet reads, special-type normalization, and write support, are outside this PR.
Why are the changes needed?
A Doris-specific entry point is needed to require vended credentials, validate the physical schema, and expose read-only capabilities. Keeping this path opt-in preserves the existing JDBC behavior by default. Physical schema checks need the table's effective Spark JDBC configuration, and existing catalog bypass settings need to remain effective in the specialized path.
Native Connector/J property names must retain their exact spelling for timeout and TLS settings to remain effective. The first Spark JDBC schema load precedes Doris validation and also needs redaction because Spark can include the full JDBC URL in connection errors. Rejecting known database-target and automatic-creation options helps contain connection side effects.
In Spark 3.5.3, JDBC metadata represents
SMALLINTasIntegerType, while the existing Gravitino JDBC table scans it asShortTypeusinggetShort(). Recognizing this specific difference avoids rejecting validSMALLINTcolumns and preserves their Spark type. The rule is confined to the Doris validator and does not change shared method/interface contracts.The specialized path uses MySQL Connector/J to access the Doris FE MySQL protocol. The driver and other required runtime dependencies remain external to the connector artifact and must be available on the Spark driver and executors.
Fix: #13489
Part of: #12846
Does this PR introduce any user-facing change?
Yes.
spark.sql.gravitino.enableDorisSupportSpark configuration key. Its default isfalse.jdbc-doriscatalog, the connector selects the governed read-only Doris path.spark.bypass.*catalog properties supply ordinary JDBC defaults; application options take precedence when keys match ignoring case. Spark read-option names are case-insensitive, but native Connector/J properties must use exact driver spelling, such asconnectTimeoutandsslMode.spark.bypass.*properties cannot override the connection URL, driver, credentials, or table/query target, or supply Spark'sprepareQuery/sessionInitStatementor the driver'sdbname/createDatabaseIfNotExist.SMALLINTremains SparkShortType, matching generic reads of the same Doris table.DATETIMEis exposed as SparkTimestampType; string rendering followsspark.sql.session.timeZone.jdbc-doriswithout the opt-in remains unchanged.Read-only capabilities reject Spark writes and catalog DDL; they do not guarantee that arbitrary JDBC driver configuration is free of connection or session side effects. Vended database credentials should have only the required read and metadata permissions.
Applications must keep
org.apache.spark.sql.execution.datasources.jdbc.connectionlogging atINFOor higher and disable JDBC driver connection/protocol tracing on both Spark drivers and executors. Adapter redaction covers physical-schema loading and validation errors; it does not sanitize arbitrary third-party logs or executor exception chains. The Doris documentation includes a Log4j 2 configuration example.How was this patch tested?
Local validation used Corretto 17.0.18, Gradle 8.2, Spark 3.5.3 / Scala 2.12, MySQL Connector/J 8.0.33, and Doris 3.0.6.2 Docker fixtures. Gravitino ran in embedded test mode.
git diff --checkpassed.TestDorisPhysicalSchemaValidator35,TestDorisPropertiesConverter35,TestDorisReadOnlyTable35, andTestGravitinoDorisCatalogSpark35, passed 26 unit tests, with zero failures, errors, or skips.driver.connect(Properties)inputs, native property spelling and override precedence, protected options at application/catalog-bypass/scan boundaries, missing credentials and driver classes, first-load redaction (URL, nested cause, and suppressed details), authorization before physical access, read-only/DDL rejection, resource closure, and safe diagnostics. TLS checks cover property forwarding and precedence only.TestGravitinoDriverPlugin.SparkJdbcDorisReadBaselineIT35suite passed 22 Doris-backed tests, with zero failures, errors, or skips: 15 parameterized scalar spelling cases, oneSMALLINTgeneric/specialized comparison, and six other read-contract regression tests.BIGINT,BOOLEAN,DATE,DATEV2, plainDATETIME,DATETIMEV2(0),DECIMAL(10,2),DECIMALV3(20,4),DOUBLE,INT,INTEGER,SMALLINT,STRING,TEXT,TINYINT, andVARCHAR(64). Each hasNOT NULLand nullable columns, non-null values, and actualNULLvalues. Aliases may resolve to the same FE/JDBC metadata type.SMALLINTcomparison reads the same Doris table through generic and specialized catalogs, checking both catalog classes, SparkShortType, JavaShortvalues, the signed bounds-32768and32767, column nullability, and actualNULLvalues._pattern matches and same-named tables in another database, write-aware load rejection, and unsupportedJSONrejection. The bypass-option test verifies correct results, zero pushed predicates, and a retained Spark residual filter whenspark.bypass.pushDownPredicate=false. The suite also runs with a catalog-level nativeconnectTimeoutdefault and an application override.The Doris suite is tagged
doris-multi-versionand was run locally with-PdorisMultiVersionTest; default Spark CI excludes that tag.Validation commands: