[BUG] LIKE-pattern Expectations never evaluate on Oracle or SingleStore — the dialect allow-list omits both, and the fallback crashes with AttributeError

Author: joshua-staufferCreated Sep 17, 2026Updated Sep 17, 2026
Labelsbughelp wantedgood first issueready-for-workclaimed

What's wrong

The four LIKE-pattern Expectations — ExpectColumnValuesToMatchLikePattern, ExpectColumnValuesToNotMatchLikePattern, ExpectColumnValuesToMatchLikePatternList, ExpectColumnValuesToNotMatchLikePatternList — never evaluate on Oracle or SingleStore. Every call returns an exception instead of a verdict, although both databases evaluate LIKE natively and every other supported SQL dialect gets a result.

All four metrics ask get_dialect_like_pattern_expression (great_expectations/expectations/metrics/util.py:950-1046) for the SQL. That helper is an allow-list: it sets dialect_supported = True for twelve named dialects, then emits plain column.like(<pattern>) — no dialect-specific translation — and returns None for anything else. Oracle and SingleStore are simply not on the list. The metrics then fall into an "unsupported dialect" branch which, in three of the four modules, crashes while building its own warning (column_values_match_like_pattern.py:29: _dialect.name on a module object that has no .name), so what the user sees is an AttributeError about a SQLAlchemy module rather than anything about LIKE.

Impact

  • Crashes: success: False with exception_info populated, for every LIKE-pattern Expectation on Oracle or SingleStore, regardless of data. The four Expectations are unusable on these two backends.
  • The error text — module 'sqlalchemy.dialects.oracle' has no attribute 'name' — points at SQLAlchemy, not at GX or at LIKE support, so users cannot tell what went wrong.
  • Present since the helper was introduced in 0.13.0, through 1.23.0.
  • Workaround: none within these Expectations. ExpectColumnValuesToMatchRegex works on Oracle (a branch for it was added in #12103); SingleStore has no equivalent.

Reproduction

Reproduced on 1.23.0 (673082d4b), Python 3.11, against the repository's own Oracle (assets/docker/oracle) and SingleStore (assets/docker/singlestore) containers.

Add to tests/integration/data_sources_and_expectations/expectations/test_expect_column_values_to_match_like_pattern.py (import OracleDatasourceTestConfig and SingleStoreDatasourceTestConfig alongside the module's other configs):

python
@parameterize_batch_for_data_sources(
    data_source_configs=[OracleDatasourceTestConfig(), SingleStoreDatasourceTestConfig()],
    data=DATA,
)
def test_like_pattern_evaluates_on_oracle_and_singlestore(batch_for_datasource: Batch) -> None:
    """Both dialects support LIKE natively, so the expectation must evaluate rather than raise.

    Every value in PREFIXED_PATTERNS starts with "foo", so ``foo%`` matches all three and the
    expectation must succeed. Today neither dialect is in the LIKE-pattern allow-list, and the
    unsupported-dialect fallback crashes with an ``AttributeError`` before it can raise the
    ``NotImplementedError`` it intends to, so the result carries an exception instead of a verdict.
    """
    result = batch_for_datasource.validate(
        gxe.ExpectColumnValuesToMatchLikePattern(column=PREFIXED_PATTERNS, like_pattern="foo%")
    )
    assert result.success, result.exception_info
bash
pytest tests/integration/data_sources_and_expectations/expectations/test_expect_column_values_to_match_like_pattern.py::test_like_pattern_evaluates_on_oracle_and_singlestore -m "oracle or singlestore"

Observed:

FAILED ...::test_like_pattern_evaluates_on_oracle_and_singlestore[oracle]
  MetricResolutionError: module 'sqlalchemy.dialects.oracle' has no attribute 'name'
FAILED ...::test_like_pattern_evaluates_on_oracle_and_singlestore[singlestore]
  MetricResolutionError: module 'sqlalchemy_singlestoredb' has no attribute 'name'
  exception_info: {"...column_values.match_like_pattern.condition...": {"raised_exception": true, ...}}

Expected:

2 passed   # success=True on both; "foo%" matches foo_abc, foo_def, foo_ghi

Requirements

  1. When any of the four LIKE-pattern Expectations runs against an Oracle or SingleStore data source, it must evaluate LIKE and return a verdict — the same success and unexpected_count that PostgreSQL, MySQL and SQLite return for the same data and pattern.
  2. Results on the twelve dialects already in the allow-list must be unchanged.
  3. When a dialect genuinely has no LIKE translation, the result must carry a clean, descriptive exception that names the dialect (the NotImplementedError the code intends), not an AttributeError raised while formatting the message.
  4. The public signatures and parameters of the four Expectations must not change.
  5. Each of the four LIKE-pattern test modules under tests/integration/data_sources_and_expectations/expectations/ must run Oracle and SingleStore in its success and failure cases, so neither dialect can drop out of the list unnoticed.

Out of scope: the regex Expectations (Snowflake's anchoring is #12213; ClickHouse's regexp_like call is a separate defect); Oracle's type-name resolution in ExpectColumnValuesToBeOfType (separate defect, same "dialect module is not a complete namespace" mistake); the LIKE escape-character feature request (#12153); inverting the allow-list to admit every SQLAlchemy dialect — a wider change touching dialects with no test coverage here.

Context

  • Fix shape, verified: with two base-class checks added inside the helper's existing if hasattr(dialect, "dialect"): block — issubclass(dialect.dialect, sa.dialects.oracle.base.OracleDialect) and issubclass(dialect.dialect, sa.dialects.mysql.base.MySQLDialect) — the test above passes on both dialects with no other change. Plain column.like is all either needs.
  • Why the existing MySQL check misses SingleStore: sqlalchemy_singlestoredb.dialect is SingleStoreDBDialect, whose MRO includes MySQLDialect, but the allow-list compares against sa.dialects.mysql.dialect, which is the default-driver subclass (MySQLDialect_mysqldb), not the base — so issubclass is False. Compare against .base.<Name>Dialect. The regex helper's Oracle branch at util.py:137 uses the same default-driver comparison; it happens to work there because the oracledb dialect subclasses the cx_oracle one.
  • The fallback crash: column_condition_partial.py:182-192 binds _dialect to execution_engine.dialect_module — a module object. column_values_match_like_pattern.py:29, ..._not_match_like_pattern.py:29 and ..._not_match_like_pattern_list.py:36 format _dialect.name and crash; ..._match_like_pattern_list.py:39 formats _dialect.dialect.name and raises the intended NotImplementedError. Aligning the three with the fourth satisfies requirement 3; moving the raise into the helper would be cleaner still.
  • Ruled out: a data or fixture problem — the same fixture and pattern pass on every allow-listed dialect the module already runs; the same two dialects pass the rest of the integration suite. Not verified: the three sibling metrics under the probe above (same helper, same list, so the same fix — but they need their own cases, hence requirement 5); whether the MySQLDialect base check admits any dialect that should stay out (MariaDB and friends also derive from it and also support LIKE).
  • Also recorded in tests/integration/data_sources_and_expectations/data_source_backlog.md ("Fifteen candidates were measured…"): these four cases are the only failures keeping SingleStore out of the gallery tier, and four of Oracle's six.

Source: fivetran/great_expectations