August 4, 2025·6 min read·engineeringcockroachdbmigrationsqloperations

CockroachDB 25.3 closes specific migration and operational gaps

Oracle data movement enters preview while functions in views and CITEXT improve SQL compatibility. CockroachDB 25.3 also changes how operators export metrics and provision directory-backed users.

Moving rows into a database does not establish that the application can run there. A migration also carries assumptions about expressions, stored logic and identity management. CockroachDB's August 4 release of version 25.3 addresses several of those boundaries separately. Oracle support in MOLT Fetch enters public preview, while SQL gains function calls in views and a case-insensitive text type.

Those changes belong to the same migration problem, but solve different parts of it. A data transfer tool can populate a target successfully while an application still depends on unsupported view definitions. Conversely, compatible SQL does not determine how a large source dataset gets loaded or how database users are provisioned after cutover.

I see CockroachDB's PostgreSQL wire compatibility as a practical adoption advantage. It makes existing client infrastructure useful, but it does not establish identical database semantics. The valuable compatibility work in this release is specific enough to evaluate against a schema or workload rather than against a general claim of familiarity.

Oracle support concerns the data movement path

The release classifies Oracle as a new source dialect for MOLT Fetch and explicitly marks that support as preview. Its availability row says the capability spans database versions. This is a tooling capability highlighted alongside the database release, rather than evidence that an Oracle migration requires every target node to run 25.3 first.

The MOLT Fetch documentation separates export from import. Fetch reads source table data into intermediate storage and then loads that data into CockroachDB. The intermediate representation provides a boundary between extracting source rows and ingesting target rows. Schema compatibility remains a prerequisite unless automatic target creation is used, and even automatic table creation does not establish that the rest of the application has been translated.

The choice of ingestion method has an availability consequence. Fetch can use IMPORT INTO, which takes the target table offline during import, or COPY FROM, which keeps it queryable. That is a decision about the target table's behavior while data arrives. It is distinct from the source database continuing to accept writes, and from how later changes reach the target.

Oracle source support therefore removes one concrete obstacle without resolving every migration dependency. A view containing application-specific logic still needs a valid target definition. Sequence state and other schema objects also have their own handling requirements. Treating data movement and SQL conversion as separate concerns makes the scope of the preview easier to understand.

Views can retain function boundaries

Version 25.3 allows views to invoke scalar and set-returning user-defined functions. The CREATE VIEW reference demonstrates both in the same view, then shows dependency tracking preventing a referenced function from being renamed. This is more than accepting another expression in a query parser. The database must retain the relationship between the stored view definition and the routines it names.

A scalar function supplies a value, while a set-returning function can supply rows to the view's query. An existing application that divides SQL logic along those boundaries can preserve that structure in more cases. Without this support, replacing the view can require duplicating function logic inside its definition or moving the composition into application code.

The documented scalar-function syntax supports a small example that exposes a computed value through a view. After defining the function, the view can use its result as a column without repeating the function body:

CREATE FUNCTION add(a INT, b INT)
RETURNS INT IMMUTABLE LANGUAGE SQL
AS 'SELECT a + b';

CREATE VIEW added_value AS
SELECT add(3, 5) AS total;

The example returns a single computed value and makes no claim about stored-procedure invocation. Although the release summary uses broad routine terminology, the detailed view examples establish the function case directly. That is the useful unit of compatibility for an application whose view calls a UDF.

Execution timing also remains significant. The UDF reference says an ordinary view invokes its function when queried. A materialized view invokes it when created or refreshed. Moving a calculation into a view therefore does not by itself cache the calculation, and replacing an ordinary view with a materialized one changes when results are produced.

CITEXT makes comparison semantics part of the column

The new CITEXT type preserves the original casing of stored values while comparing them without case sensitivity. This avoids requiring every query author to remember to apply a normalization expression. The declaration gives the column an explicit comparison rule that follows it into equality and ordering operations.

For example, the documented behavior supports storing Roach and finding it with a lowercase predicate. This example asks for the original value rather than a normalized replacement, so the result retains the casing supplied at insertion:

CREATE TABLE logins (username CITEXT);
INSERT INTO logins VALUES ('Roach');
SELECT username FROM logins WHERE username = 'roach';

Case insensitivity does not mean every textual distinction disappears. CockroachDB documents the type as equivalent in comparison behavior to the und-u-ks-level2 collation, which is accent-sensitive. An application migrating from another text comparison scheme needs to compare the actual rules, especially when those rules determine whether identifiers are considered equal.

The implementation also has a cost. The type reference describes extra CPU and memory consumption because comparisons use a collation engine. An explicit cast to STRING requests case-sensitive comparison when needed. Those details make CITEXT a semantic choice rather than a general replacement for ordinary strings.

I prefer declaring this rule in the schema when case-insensitive comparison is part of the data model. It reduces the opportunity for two query paths to disagree about the same value. The benefit depends on the type matching the intended rule, including its treatment of accents.

Metrics acquire a dimensional representation

The new Prometheus endpoint, available in preview at /metrics, changes how related measurements are represented. Existing /_status/vars output exports separate SQL operation names such as sql_insert_count and sql_select_count. The new endpoint can represent those operations with sql_count and a query_type label.

That changes the query interface to monitoring data. An aggregate over all operation types can use a shared metric name rather than enumerate each operation-specific name. Filtering by operation becomes a label selection. Existing alerts written against the old names still embody the old representation, so changing the scrape path is not sufficient to translate them.

Labels also carry categories that should not necessarily be summed. The documentation uses certificate expiration as an example. Certificate type can distinguish several expiration measurements under a shared name, but adding their timestamps would not produce a useful expiration time. A dimensional metric model improves selection and presentation without making every aggregation meaningful.

This is an operational compatibility change alongside the SQL changes. Dashboards and alerts are consumers with their own assumptions about names and dimensions. The new representation can simplify those consumers, provided their expressions use the intended labels and preserve each metric's meaning.

Storage has a separate preview boundary

Version 25.3 also introduces value separation in preview, disabled by default. Large values can live in blob files outside the log-structured merge tree, with pointers stored alongside their keys. Compaction can then copy those pointers instead of repeatedly rewriting the large values. This targets storage write amplification rather than changing application SQL. Its separate enablement matters when attributing performance changes to an upgrade, because installing the release does not establish that value separation is active.

Directory authentication can create the database user

Automatic LDAP-backed provisioning removes a separate account-creation step. The LDAP configuration reference describes creating the SQL user on the first successful directory authentication. Auto-provisioned users receive a PROVISIONSRC role option, and the system tracks an estimated last login time for auditing.

Authentication and authorization remain separate operations. Directory authentication verifies credentials. Optional LDAP authorization maps directory group membership to existing CockroachDB roles. Creating a user alone does not establish that the user has the application's intended privileges, which is why the documentation recommends configuring authorization with provisioning.

The account lifecycle also extends beyond successful login. The configuration reference explicitly describes cleaning up users removed or deactivated in Active Directory, because those users are not automatically dropped from CockroachDB. Automatic creation should therefore not be read as an assertion that every account-management action has become automatic.

Finally, some new behavior depends on upgrade finalization. The 25.3 finalization requirements include CITEXT and automatic LDAP provisioning. Upgrading binaries and making these features available are separate stages. A migration that needs either capability must account for the finalized cluster version, in addition to the SQL definitions and directory configuration that use it.