Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,7 @@ public void createSchema(Session session, CatalogSchemaName schema, Map<String,
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, schema.getCatalogName());
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);
metadata.createSchema(session.toConnectorSession(catalogHandle), schema.getSchemaName(), properties, principal);
metadata.createSchema(session.toConnectorSession(catalogHandle), schema.getSchema(), properties, principal);
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.schemaCreated(session, schema);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import io.trino.spi.TrinoException;
import io.trino.spi.connector.CatalogSchemaName;
import io.trino.spi.connector.ColumnMetadata;
import io.trino.spi.connector.ConnectorIdentifier;
import io.trino.spi.connector.ConnectorTableMetadata;
import io.trino.spi.connector.EntityKindAndName;
import io.trino.spi.connector.SchemaTableName;
Expand Down Expand Up @@ -166,6 +167,8 @@ public static CatalogSchemaName createCatalogSchemaName(Session session, Node no
{
String catalogName = session.getCatalog().orElse(null);
String schemaName = session.getSchema().orElse(null);
boolean isCatalogDelimited = false;
boolean isSchemaDelimited = false;

if (schema.isPresent()) {
List<String> parts = schema.get().getParts();
Expand All @@ -174,8 +177,10 @@ public static CatalogSchemaName createCatalogSchemaName(Session session, Node no
}
if (parts.size() == 2) {
catalogName = parts.get(0);
isCatalogDelimited = schema.get().isDelimitedPart(0);
}
schemaName = schema.get().getSuffix();
isSchemaDelimited = schema.get().isDelimitedSuffix();
}

if (catalogName == null) {
Expand All @@ -185,7 +190,9 @@ public static CatalogSchemaName createCatalogSchemaName(Session session, Node no
throw semanticException(MISSING_SCHEMA_NAME, node, "Schema must be specified when session schema is not set");
}

return new CatalogSchemaName(catalogName, schemaName);
return new CatalogSchemaName(
new ConnectorIdentifier(catalogName, isCatalogDelimited),
new ConnectorIdentifier(schemaName, isSchemaDelimited));
}

public static QualifiedObjectName createQualifiedObjectName(Session session, Node node, QualifiedName name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.trino.spi.connector.ColumnPosition;
import io.trino.spi.connector.ConnectorAccessControl;
import io.trino.spi.connector.ConnectorAnalyzeMetadata;
import io.trino.spi.connector.ConnectorIdentifier;
import io.trino.spi.connector.ConnectorInsertTableHandle;
import io.trino.spi.connector.ConnectorMaterializedViewDefinition;
import io.trino.spi.connector.ConnectorMergeTableHandle;
Expand Down Expand Up @@ -351,6 +352,15 @@ public void createSchema(ConnectorSession session, String schemaName, Map<String
}
}

@Override
public void createSchema(ConnectorSession session, ConnectorIdentifier schema, Map<String, Object> properties, TrinoPrincipal owner)
{
Span span = startSpan("createSchema", schema.getValue());
try (var _ = scopedSpan(span)) {
delegate.createSchema(session, schema, properties, owner);
}
}

@Override
public void dropSchema(ConnectorSession session, String schemaName, boolean cascade)
{
Expand All @@ -362,9 +372,28 @@ public void dropSchema(ConnectorSession session, String schemaName, boolean casc
}

@Override
public void renameSchema(ConnectorSession session, String source, String target)
public void dropSchema(ConnectorSession session, ConnectorIdentifier schema, boolean cascade)
{
Span span = startSpan("dropSchema", schema.getValue())
.setAttribute(TrinoAttributes.CASCADE, cascade);
try (var _ = scopedSpan(span)) {
delegate.dropSchema(session, schema, cascade);
}
}

@Override
public void renameSchema(ConnectorSession session, String schemaName, String newSchemaName)
{
Span span = startSpan("renameSchema", schemaName);
try (var _ = scopedSpan(span)) {
delegate.renameSchema(session, schemaName, newSchemaName);
}
}

@Override
public void renameSchema(ConnectorSession session, ConnectorIdentifier source, ConnectorIdentifier target)
{
Span span = startSpan("renameSchema", source);
Span span = startSpan("renameSchema", source.getValue());
try (var _ = scopedSpan(span)) {
delegate.renameSchema(session, source, target);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import io.trino.spi.connector.Connector;
import io.trino.spi.connector.ConnectorAccessControl;
import io.trino.spi.connector.ConnectorCapabilities;
import io.trino.spi.connector.ConnectorIdentifier;
import io.trino.spi.connector.ConnectorInsertTableHandle;
import io.trino.spi.connector.ConnectorMaterializedViewDefinition;
import io.trino.spi.connector.ConnectorMergeSink;
Expand Down Expand Up @@ -529,16 +530,16 @@ public List<String> listSchemaNames(ConnectorSession session)
}

@Override
public void createSchema(ConnectorSession session, String schemaName, Map<String, Object> properties, TrinoPrincipal owner) {}
public void createSchema(ConnectorSession session, ConnectorIdentifier schemaName, Map<String, Object> properties, TrinoPrincipal owner) {}

@Override
public void renameSchema(ConnectorSession session, String source, String target) {}
public void renameSchema(ConnectorSession session, ConnectorIdentifier source, ConnectorIdentifier target) {}

@Override
public void setSchemaAuthorization(ConnectorSession session, String schemaName, TrinoPrincipal principal) {}

@Override
public void dropSchema(ConnectorSession session, String schemaName, boolean cascade) {}
public void dropSchema(ConnectorSession session, ConnectorIdentifier schemaName, boolean cascade) {}

@Override
public ConnectorTableHandle getTableHandle(ConnectorSession session, SchemaTableName tableName, Optional<ConnectorTableVersion> startVersion, Optional<ConnectorTableVersion> endVersion)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,22 @@ public List<String> getParts()
return parts;
}

public boolean isDelimitedPart(int part)
{
if (part >= 0 && part < originalParts.size()) {
return originalParts.get(part).isDelimited();
}
return false;
}

public boolean isDelimitedSuffix()
{
if (!originalParts.isEmpty()) {
return originalParts.getFirst().isDelimited();
}
return false;
}

public List<Identifier> getOriginalParts()
{
return originalParts;
Expand Down
24 changes: 24 additions & 0 deletions core/trino-spi/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,30 @@
<new>method io.trino.spi.function.FunctionMetadata io.trino.spi.function.FunctionMetadata::fromJson(io.trino.spi.function.FunctionId, io.trino.spi.function.Signature, java.lang.String, java.util.Set&lt;java.lang.String&gt;, io.trino.spi.function.FunctionNullability, boolean, boolean, boolean, java.lang.String, io.trino.spi.function.FunctionKind, boolean)</new>
<justification>Function declares whether it never fails</justification>
</item>
<item>
<ignore>true</ignore>
<code>java.annotation.removed</code>
<old>method void io.trino.spi.connector.CatalogSchemaName::&lt;init&gt;(java.lang.String, java.lang.String)</old>
<new>method void io.trino.spi.connector.CatalogSchemaName::&lt;init&gt;(java.lang.String, java.lang.String)</new>
<annotation>@com.fasterxml.jackson.annotation.JsonCreator</annotation>
<justification>Use of ConnectorIdentifier</justification>
</item>
<item>
<ignore>true</ignore>
<code>java.annotation.removed</code>
<old>parameter void io.trino.spi.connector.CatalogSchemaName::&lt;init&gt;(===java.lang.String===, java.lang.String)</old>
<new>parameter void io.trino.spi.connector.CatalogSchemaName::&lt;init&gt;(===java.lang.String===, java.lang.String)</new>
<annotation>@com.fasterxml.jackson.annotation.JsonProperty("catalogName")</annotation>
<justification>Use of ConnectorIdentifier</justification>
</item>
<item>
<ignore>true</ignore>
<code>java.annotation.removed</code>
<old>parameter void io.trino.spi.connector.CatalogSchemaName::&lt;init&gt;(java.lang.String, ===java.lang.String===)</old>
<new>parameter void io.trino.spi.connector.CatalogSchemaName::&lt;init&gt;(java.lang.String, ===java.lang.String===)</new>
<annotation>@com.fasterxml.jackson.annotation.JsonProperty("schemaName")</annotation>
<justification>Use of ConnectorIdentifier</justification>
</item>
</differences>
</revapi.differences>
</analysisConfiguration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,52 @@

import java.util.Objects;

import static java.util.Locale.ENGLISH;
import static java.util.Objects.requireNonNull;

public final class CatalogSchemaName
{
private final String catalogName;
private final String schemaName;
private final ConnectorIdentifier catalog;
private final ConnectorIdentifier schema;

@JsonCreator
public CatalogSchemaName(
@JsonProperty("catalogName") String catalogName,
@JsonProperty("schemaName") String schemaName)
@JsonProperty("catalog") ConnectorIdentifier catalog,
@JsonProperty("schema") ConnectorIdentifier schema)
{
this.catalogName = catalogName.toLowerCase(ENGLISH);
this.schemaName = schemaName.toLowerCase(ENGLISH);
this.catalog = requireNonNull(catalog, "catalog is null");
this.schema = requireNonNull(schema, "schema is null");
}

public CatalogSchemaName(
String catalog,
String schema)
{
this.catalog = new ConnectorIdentifier(catalog, false);
this.schema = new ConnectorIdentifier(schema, false);
}

@JsonProperty
public ConnectorIdentifier getCatalog()
{
return catalog;
}

@JsonProperty
public ConnectorIdentifier getSchema()
{
return schema;
}

@JsonProperty
public String getCatalogName()
{
return catalogName;
return catalog.getValue();
}

@JsonProperty
public String getSchemaName()
{
return schemaName;
return schema.getValue();
}

@Override
Expand All @@ -56,19 +76,19 @@ public boolean equals(Object obj)
return false;
}
CatalogSchemaName that = (CatalogSchemaName) obj;
return Objects.equals(catalogName, that.catalogName) &&
Objects.equals(schemaName, that.schemaName);
return Objects.equals(catalog, that.catalog) &&
Objects.equals(schema, that.schema);
}

@Override
public int hashCode()
{
return Objects.hash(catalogName, schemaName);
return Objects.hash(catalog, schema);
}

@Override
public String toString()
{
return catalogName + '.' + schemaName;
return catalog.getValue() + '.' + schema.getValue();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.trino.spi.connector;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Objects;

import static java.util.Locale.ENGLISH;
import static java.util.Objects.requireNonNull;

public class ConnectorIdentifier
{
private final String value;
private final boolean delimited;
Comment on lines +24 to +27
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.

Names coming from connectors don't have a delimited / non-delimited characteristic. They are already canonicalized. The delimited characteristic only pertains to identifiers parsed from a SQL query, and matters only for deciding how to match identifiers to names.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Names coming from connectors don't have a delimited / non-delimited characteristic.

Regarding the identifiers coming from the connectors, I agree. But here we're talking about identifiers coming from Trino tasks and destined for the connectors in order to execute the appropriate DDL commands.

If we want to be able to manage delimited and undelimited identifiers and compare them according to the underlying database rules. For example:

  • in HsqlDB (uppercase) "PUBLIC".Table1 is the same identifier as public."TABLE1"

  • in SQLite (lowercase) "main".Table1 is the same identifier as MAIN."table1"

If we need to test whether a schema exists before its creation, I don't see any other way without using the ConnectorIdentifier class, which allows these comparisons between identifiers.

I'd like you to explain how you plan to solve this problem, because so far I haven't found anything better?

Copy link
Copy Markdown
Member Author

@prrvchr prrvchr Feb 20, 2026

Choose a reason for hiding this comment

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

@martint I think I understand what you were trying to tell me.

You're saying that Trino must normalize (ie: canonalize) all undelimited identifiers and that, therefore, all identifiers received by connectors must be considered as delimited identifiers.

Can you confirm this? Please excuse my lack of understanding.


@JsonCreator
public ConnectorIdentifier(String value, boolean delimited)
{
this.value = requireNonNull(value, "value is null");
this.delimited = delimited;
}

@JsonProperty
public String getValue()
{
return delimited ? value : canonicalize();
}

@JsonProperty
public boolean isDelimited()
{
return delimited;
}

@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ConnectorIdentifier that = (ConnectorIdentifier) o;
return Objects.equals(this.getValue(), that.getValue());
}

@Override
public int hashCode()
{
return Objects.hash(value, delimited);
}

@Override
public String toString()
{
return value;
}

private String canonicalize()
{
return value.toLowerCase(ENGLISH);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,14 @@ default TableStatistics getTableStatistics(ConnectorSession session, ConnectorTa
* Creates a schema.
*/
default void createSchema(ConnectorSession session, String schemaName, Map<String, Object> properties, TrinoPrincipal owner)
{
createSchema(session, new ConnectorIdentifier(schemaName, true), properties, owner);
}

/**
* Creates a schema.
*/
default void createSchema(ConnectorSession session, ConnectorIdentifier schema, Map<String, Object> properties, TrinoPrincipal owner)
{
throw new TrinoException(NOT_SUPPORTED, "This connector does not support creating schemas");
}
Expand All @@ -454,6 +462,16 @@ default void createSchema(ConnectorSession session, String schemaName, Map<Strin
* @throws TrinoException with {@code SCHEMA_NOT_EMPTY} if {@code cascade} is false and the schema is not empty
*/
default void dropSchema(ConnectorSession session, String schemaName, boolean cascade)
{
dropSchema(session, new ConnectorIdentifier(schemaName, true), cascade);
}

/**
* Drops the specified schema.
*
* @throws TrinoException with {@code SCHEMA_NOT_EMPTY} if {@code cascade} is false and the schema is not empty
*/
default void dropSchema(ConnectorSession session, ConnectorIdentifier schema, boolean cascade)
{
throw new TrinoException(NOT_SUPPORTED, "This connector does not support dropping schemas");
}
Expand All @@ -462,6 +480,14 @@ default void dropSchema(ConnectorSession session, String schemaName, boolean cas
* Renames the specified schema.
*/
default void renameSchema(ConnectorSession session, String source, String target)
{
renameSchema(session, new ConnectorIdentifier(source, true), new ConnectorIdentifier(target, true));
}

/**
* Renames the specified schema.
*/
default void renameSchema(ConnectorSession session, ConnectorIdentifier source, ConnectorIdentifier target)
{
throw new TrinoException(NOT_SUPPORTED, "This connector does not support renaming schemas");
}
Expand Down
Loading
Loading