Skip to content

[SPARK-56611][SQL] Fix ALTER TABLE RENAME TO with catalog-qualified and table-only targets#55547

Open
lunar-shadow wants to merge 3 commits intoapache:masterfrom
lunar-shadow:fix/rename-table-with-catalog
Open

[SPARK-56611][SQL] Fix ALTER TABLE RENAME TO with catalog-qualified and table-only targets#55547
lunar-shadow wants to merge 3 commits intoapache:masterfrom
lunar-shadow:fix/rename-table-with-catalog

Conversation

@lunar-shadow
Copy link
Copy Markdown

@lunar-shadow lunar-shadow commented Apr 24, 2026

What changes were proposed in this pull request?

This fixes ALTER TABLE ... RENAME TO in V2 catalogs for two cases that weren't handled correctly:

  • When the target name is catalog-qualified
  • When the target is just a table name (no namespace)

Changes:

  • Strip the catalog prefix from the target when it matches the source catalog
  • Inherit source namespace when target is table-only
  • Add tests covering the above cases

Why are the changes needed?

Right now, rename behaves incorrectly in a few scenarios.

For example:

ALTER TABLE testcat.ns.t1 RENAME TO testcat.ns.t2;

fails because asIdentifier treats everything except the last part as the namespace. That means the catalog name (testcat) incorrectly ends up inside the namespace:

Identifier.of(["testcat", "ns"], "t2")

instead of:

Identifier.of(["ns"], "t2")

Similarly:

ALTER TABLE testcat.ns.t1 RENAME TO t2;

creates an identifier with an empty namespace, instead of inheriting ns from the source table.

Steps to reproduce:

CREATE TABLE testcat.ns.t1 USING foo AS SELECT 1 AS id;
ALTER TABLE testcat.ns.t1 RENAME TO testcat.ns.t2;

This fails with a namespace resolution error due to the catalog being treated as part of the namespace.

Does this PR introduce any user-facing change?

Yes.

  • Catalog-qualified renames like ALTER TABLE catalog.ns.t1 RENAME TO catalog.ns.t2 now work correctly
  • Renaming to a table-only name (e.g., RENAME TO t2) now correctly keeps the original namespace
  • Cross-namespace renames (e.g., RENAME TO other_ns.t2) continue to work as before

How was this patch tested?

Added tests in DataSourceV2SQLSuite covering catalog-qualified renames, table-only renames, and cross-namespace renames.

Was this patch authored or co-authored using generative AI tooling?

No

@lunar-shadow lunar-shadow force-pushed the fix/rename-table-with-catalog branch from 669a517 to 8163d49 Compare April 24, 2026 20:04
@lunar-shadow lunar-shadow force-pushed the fix/rename-table-with-catalog branch from 8163d49 to cf3a248 Compare April 25, 2026 05:00

// Strip catalog prefix if the identifier is catalog-qualified.
val newNameParts =
if (rawNewNameParts.length > 1 && rawNewNameParts.head == catalog.name()) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This looks like case-sensitive for catalog names which is incorrect, doesn't it? Please add a unit test case like the following?

ALTER TABLE testcat.ns.t1 RENAME TO TesTcaT.ns.t1_renamed

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks @dongjoon-hyun for catching this.

Fixed, now using SQLConf.get.resolver for case-insensitive comparison. Added a test case: ALTER TABLE testcat.ns.t1_renamed RENAME TO TesTcaT.ns.t1

}

val namespace =
if (newNameParts.length == 1) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please follow the community Scala coding style for val namespace = if (...) {.

val ret = if (condition) {
  Seq(1, 2, 3)
} else {
  Seq(1, 2, 3)
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed, thanks.

}
}

test("SPARK-56611: rename table across namespace should work for V2 catalogs") {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We don't need to mention for V2 catalogs phrase because this is inside DataSourceV2SQLSuite.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done, renamed to "rename table across namespaces"

if (newNameParts.length == 1) {
oldIdent.namespace()
} else {
newNameParts.dropRight(1).toArray
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In this case, we can use init.toArray like asIdentifier.

def asIdentifier: Identifier = Identifier.of(parts.init.toArray, parts.last)

- newNameParts.dropRight(1).toArray
+ newNameParts.init.toArray

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed, thanks.

sql("CREATE TABLE testcat.ns1.t1 USING foo AS SELECT id, data FROM source")
checkAnswer(sql("SHOW TABLES FROM testcat.ns1"), Seq(Row("ns1", "t1", false)))

sql("ALTER TABLE testcat.ns1.t1 RENAME TO ns2.t1")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Dose this PR aim to support ALTER TABLE testcat.ns1.t1 RENAME TO othercat.ns2.t1? Could you add a test case?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Cross-catalog rename is not addressed as part of this PR. I noticed it currently silently treats the other catalog name as a namespace. I'll file a follow-up JIRA for proper validation.

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.

Shouldn't the above be interpreted as move (rename) t1 table from ns1 namespace to othercat.ns2 namespace in testcat catalog? So doesn't the current PR work as expected?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Right, cross-catalog rename may not be a valid operation as RENAME operates within a single catalog. So othercat.ns2.t1 is correctly treated as a namespace path within testcat. Added a test case to verify this. No follow-up needed, thanks for the clarification.

if (rawNewNameParts.length > 1 && rawNewNameParts.head == catalog.name()) {
rawNewNameParts.tail
} else {
rawNewNameParts
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we have a test case for this?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes, both RENAME TO testcat.ns.t1_renamed and RENAME TO TesTcaT.ns.t1 in the test hit this code path.

@dongjoon-hyun
Copy link
Copy Markdown
Member

cc @peter-toth , too.

Comment on lines +464 to +470
val namespace = if (newNameParts.length == 1) {
oldIdent.namespace()
} else {
newNameParts.init.toArray
}

val newIdent = Identifier.of(namespace, newNameParts.last)
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.

Minor nit:

Suggested change
val namespace = if (newNameParts.length == 1) {
oldIdent.namespace()
} else {
newNameParts.init.toArray
}
val newIdent = Identifier.of(namespace, newNameParts.last)
val newIdent = if (newNameParts.length == 1) {
Identifier.of(oldIdent.namespace(), newNameParts.last)
} else {
newNameParts.asIdentifier
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

adopted this change, thanks!

sql("CREATE TABLE testcat.ns1.t1 USING foo AS SELECT id, data FROM source")
checkAnswer(sql("SHOW TABLES FROM testcat.ns1"), Seq(Row("ns1", "t1", false)))

sql("ALTER TABLE testcat.ns1.t1 RENAME TO ns2.t1")
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.

Shouldn't the above be interpreted as move (rename) t1 table from ns1 namespace to othercat.ns2 namespace in testcat catalog? So doesn't the current PR work as expected?

@peter-toth
Copy link
Copy Markdown
Contributor

cc @cloud-fan, @gengliangwang

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.

3 participants