diff --git a/plugin/trino-accumulo/src/test/java/io/trino/plugin/accumulo/TestAccumuloConnectorTest.java b/plugin/trino-accumulo/src/test/java/io/trino/plugin/accumulo/TestAccumuloConnectorTest.java index bcebbe2da7fe..d906cc965e39 100644 --- a/plugin/trino-accumulo/src/test/java/io/trino/plugin/accumulo/TestAccumuloConnectorTest.java +++ b/plugin/trino-accumulo/src/test/java/io/trino/plugin/accumulo/TestAccumuloConnectorTest.java @@ -81,6 +81,9 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) case SUPPORTS_NOT_NULL_CONSTRAINT: return false; + case SUPPORTS_ROW_TYPE: + return false; + default: return super.hasBehavior(connectorBehavior); } diff --git a/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/TestJdbcConnectorTest.java b/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/TestJdbcConnectorTest.java index 8cd057ef659c..61aef98104f4 100644 --- a/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/TestJdbcConnectorTest.java +++ b/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/TestJdbcConnectorTest.java @@ -70,6 +70,7 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) return false; case SUPPORTS_ARRAY: + case SUPPORTS_ROW_TYPE: return false; default: diff --git a/plugin/trino-cassandra/src/main/java/io/trino/plugin/cassandra/CassandraType.java b/plugin/trino-cassandra/src/main/java/io/trino/plugin/cassandra/CassandraType.java index 98869f9245f9..663188809387 100644 --- a/plugin/trino-cassandra/src/main/java/io/trino/plugin/cassandra/CassandraType.java +++ b/plugin/trino-cassandra/src/main/java/io/trino/plugin/cassandra/CassandraType.java @@ -30,6 +30,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.net.InetAddresses; import io.airlift.slice.Slice; +import io.trino.spi.TrinoException; import io.trino.spi.block.Block; import io.trino.spi.block.RowBlockBuilder; import io.trino.spi.block.SingleRowBlockWriter; @@ -70,6 +71,7 @@ import static io.airlift.slice.Slices.wrappedBuffer; import static io.trino.plugin.cassandra.util.CassandraCqlUtils.quoteStringLiteral; import static io.trino.plugin.cassandra.util.CassandraCqlUtils.quoteStringLiteralForJson; +import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED; import static io.trino.spi.type.DateTimeEncoding.packDateTimeWithZone; import static io.trino.spi.type.DateTimeEncoding.unpackMillisUtc; import static io.trino.spi.type.TypeUtils.writeNativeValue; @@ -662,7 +664,7 @@ public static CassandraType toCassandraType(Type type, ProtocolVersion protocolV if (type.equals(UuidType.UUID)) { return CassandraTypes.UUID; } - throw new IllegalArgumentException("unsupported type: " + type); + throw new TrinoException(NOT_SUPPORTED, "Unsupported type: " + type); } @Override diff --git a/plugin/trino-cassandra/src/test/java/io/trino/plugin/cassandra/TestCassandraConnectorTest.java b/plugin/trino-cassandra/src/test/java/io/trino/plugin/cassandra/TestCassandraConnectorTest.java index e1b2a6269da3..66e8c9a28e6e 100644 --- a/plugin/trino-cassandra/src/test/java/io/trino/plugin/cassandra/TestCassandraConnectorTest.java +++ b/plugin/trino-cassandra/src/test/java/io/trino/plugin/cassandra/TestCassandraConnectorTest.java @@ -99,6 +99,7 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) return false; case SUPPORTS_ARRAY: + case SUPPORTS_ROW_TYPE: return false; case SUPPORTS_ADD_COLUMN: diff --git a/plugin/trino-clickhouse/src/test/java/io/trino/plugin/clickhouse/TestClickHouseConnectorTest.java b/plugin/trino-clickhouse/src/test/java/io/trino/plugin/clickhouse/TestClickHouseConnectorTest.java index 4ace78749914..4bd8367e41e5 100644 --- a/plugin/trino-clickhouse/src/test/java/io/trino/plugin/clickhouse/TestClickHouseConnectorTest.java +++ b/plugin/trino-clickhouse/src/test/java/io/trino/plugin/clickhouse/TestClickHouseConnectorTest.java @@ -82,6 +82,9 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) return false; case SUPPORTS_ARRAY: + case SUPPORTS_ROW_TYPE: + return false; + case SUPPORTS_NEGATIVE_DATE: return false; diff --git a/plugin/trino-kudu/src/test/java/io/trino/plugin/kudu/AbstractKuduConnectorTest.java b/plugin/trino-kudu/src/test/java/io/trino/plugin/kudu/AbstractKuduConnectorTest.java index 95ef84459653..bb34bc350ab5 100644 --- a/plugin/trino-kudu/src/test/java/io/trino/plugin/kudu/AbstractKuduConnectorTest.java +++ b/plugin/trino-kudu/src/test/java/io/trino/plugin/kudu/AbstractKuduConnectorTest.java @@ -76,6 +76,10 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) case SUPPORTS_NOT_NULL_CONSTRAINT: case SUPPORTS_TOPN_PUSHDOWN: return false; + + case SUPPORTS_ROW_TYPE: + return false; + default: return super.hasBehavior(connectorBehavior); } diff --git a/plugin/trino-mysql/src/test/java/io/trino/plugin/mysql/BaseMySqlConnectorTest.java b/plugin/trino-mysql/src/test/java/io/trino/plugin/mysql/BaseMySqlConnectorTest.java index bba20330e2c0..d6e305d639ea 100644 --- a/plugin/trino-mysql/src/test/java/io/trino/plugin/mysql/BaseMySqlConnectorTest.java +++ b/plugin/trino-mysql/src/test/java/io/trino/plugin/mysql/BaseMySqlConnectorTest.java @@ -66,6 +66,9 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) return false; case SUPPORTS_ARRAY: + case SUPPORTS_ROW_TYPE: + return false; + case SUPPORTS_NEGATIVE_DATE: return false; diff --git a/plugin/trino-oracle/src/test/java/io/trino/plugin/oracle/BaseOracleConnectorTest.java b/plugin/trino-oracle/src/test/java/io/trino/plugin/oracle/BaseOracleConnectorTest.java index ae84981a7454..ffe3358bee2f 100644 --- a/plugin/trino-oracle/src/test/java/io/trino/plugin/oracle/BaseOracleConnectorTest.java +++ b/plugin/trino-oracle/src/test/java/io/trino/plugin/oracle/BaseOracleConnectorTest.java @@ -64,6 +64,7 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) return false; case SUPPORTS_ARRAY: + case SUPPORTS_ROW_TYPE: return false; case SUPPORTS_CREATE_SCHEMA: diff --git a/plugin/trino-phoenix/src/test/java/io/trino/plugin/phoenix/TestPhoenixConnectorTest.java b/plugin/trino-phoenix/src/test/java/io/trino/plugin/phoenix/TestPhoenixConnectorTest.java index 5de2809adeab..d2c36187533e 100644 --- a/plugin/trino-phoenix/src/test/java/io/trino/plugin/phoenix/TestPhoenixConnectorTest.java +++ b/plugin/trino-phoenix/src/test/java/io/trino/plugin/phoenix/TestPhoenixConnectorTest.java @@ -85,6 +85,9 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) case SUPPORTS_NOT_NULL_CONSTRAINT: return false; + case SUPPORTS_ROW_TYPE: + return false; + default: return super.hasBehavior(connectorBehavior); } diff --git a/plugin/trino-phoenix5/src/test/java/io/trino/plugin/phoenix5/TestPhoenixConnectorTest.java b/plugin/trino-phoenix5/src/test/java/io/trino/plugin/phoenix5/TestPhoenixConnectorTest.java index 313058ccf78e..db1f3a37d7ef 100644 --- a/plugin/trino-phoenix5/src/test/java/io/trino/plugin/phoenix5/TestPhoenixConnectorTest.java +++ b/plugin/trino-phoenix5/src/test/java/io/trino/plugin/phoenix5/TestPhoenixConnectorTest.java @@ -103,6 +103,9 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) case SUPPORTS_NOT_NULL_CONSTRAINT: return false; + case SUPPORTS_ROW_TYPE: + return false; + default: return super.hasBehavior(connectorBehavior); } diff --git a/plugin/trino-postgresql/src/test/java/io/trino/plugin/postgresql/TestPostgreSqlConnectorTest.java b/plugin/trino-postgresql/src/test/java/io/trino/plugin/postgresql/TestPostgreSqlConnectorTest.java index d4167c3ea38f..5e3f9a737cfd 100644 --- a/plugin/trino-postgresql/src/test/java/io/trino/plugin/postgresql/TestPostgreSqlConnectorTest.java +++ b/plugin/trino-postgresql/src/test/java/io/trino/plugin/postgresql/TestPostgreSqlConnectorTest.java @@ -127,6 +127,9 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) // Arrays are supported conditionally. Check the defaults. return new PostgreSqlConfig().getArrayMapping() != PostgreSqlConfig.ArrayMapping.DISABLED; + case SUPPORTS_ROW_TYPE: + return false; + case SUPPORTS_RENAME_TABLE_ACROSS_SCHEMAS: return false; diff --git a/plugin/trino-raptor-legacy/src/main/java/io/trino/plugin/raptor/legacy/storage/OrcFileWriter.java b/plugin/trino-raptor-legacy/src/main/java/io/trino/plugin/raptor/legacy/storage/OrcFileWriter.java index 26a878f7e213..dc8605e4d1da 100644 --- a/plugin/trino-raptor-legacy/src/main/java/io/trino/plugin/raptor/legacy/storage/OrcFileWriter.java +++ b/plugin/trino-raptor-legacy/src/main/java/io/trino/plugin/raptor/legacy/storage/OrcFileWriter.java @@ -329,6 +329,6 @@ private static StorageType toStorageType(Type type) if (isMapType(type)) { return mapOf(toStorageType(type.getTypeParameters().get(0)), toStorageType(type.getTypeParameters().get(1))); } - throw new TrinoException(NOT_SUPPORTED, "No storage type for type: " + type); + throw new TrinoException(NOT_SUPPORTED, "Unsupported type: " + type); } } diff --git a/plugin/trino-raptor-legacy/src/test/java/io/trino/plugin/raptor/legacy/BaseRaptorConnectorTest.java b/plugin/trino-raptor-legacy/src/test/java/io/trino/plugin/raptor/legacy/BaseRaptorConnectorTest.java index ca82b34c9e74..de965d4666a0 100644 --- a/plugin/trino-raptor-legacy/src/test/java/io/trino/plugin/raptor/legacy/BaseRaptorConnectorTest.java +++ b/plugin/trino-raptor-legacy/src/test/java/io/trino/plugin/raptor/legacy/BaseRaptorConnectorTest.java @@ -77,6 +77,10 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) case SUPPORTS_NOT_NULL_CONSTRAINT: case SUPPORTS_TOPN_PUSHDOWN: return false; + + case SUPPORTS_ROW_TYPE: + return false; + default: return super.hasBehavior(connectorBehavior); } diff --git a/plugin/trino-singlestore/src/test/java/io/trino/plugin/singlestore/TestSingleStoreConnectorTest.java b/plugin/trino-singlestore/src/test/java/io/trino/plugin/singlestore/TestSingleStoreConnectorTest.java index cc002f370d27..accc35f71d34 100644 --- a/plugin/trino-singlestore/src/test/java/io/trino/plugin/singlestore/TestSingleStoreConnectorTest.java +++ b/plugin/trino-singlestore/src/test/java/io/trino/plugin/singlestore/TestSingleStoreConnectorTest.java @@ -84,6 +84,7 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) return false; case SUPPORTS_ARRAY: + case SUPPORTS_ROW_TYPE: return false; case SUPPORTS_RENAME_SCHEMA: diff --git a/plugin/trino-sqlserver/src/test/java/io/trino/plugin/sqlserver/BaseSqlServerConnectorTest.java b/plugin/trino-sqlserver/src/test/java/io/trino/plugin/sqlserver/BaseSqlServerConnectorTest.java index 0c565268a844..9be8069fd1db 100644 --- a/plugin/trino-sqlserver/src/test/java/io/trino/plugin/sqlserver/BaseSqlServerConnectorTest.java +++ b/plugin/trino-sqlserver/src/test/java/io/trino/plugin/sqlserver/BaseSqlServerConnectorTest.java @@ -75,6 +75,9 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) return false; case SUPPORTS_ARRAY: + case SUPPORTS_ROW_TYPE: + return false; + case SUPPORTS_NEGATIVE_DATE: return false; diff --git a/testing/trino-testing/src/main/java/io/trino/testing/BaseConnectorTest.java b/testing/trino-testing/src/main/java/io/trino/testing/BaseConnectorTest.java index 124dd7f2b620..ab53f4961f85 100644 --- a/testing/trino-testing/src/main/java/io/trino/testing/BaseConnectorTest.java +++ b/testing/trino-testing/src/main/java/io/trino/testing/BaseConnectorTest.java @@ -93,6 +93,7 @@ import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_RENAME_TABLE; import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_RENAME_TABLE_ACROSS_SCHEMAS; import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_ROW_LEVEL_DELETE; +import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_ROW_TYPE; import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_TOPN_PUSHDOWN; import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_TRUNCATE; import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_UPDATE; @@ -2855,11 +2856,8 @@ private void testDataMapping(DataMappingTestSetup dataMappingTestSetup) assertUpdate(createTable, 3); }; if (dataMappingTestSetup.isUnsupportedType()) { - String typeNameBase = trinoTypeName.replaceFirst("\\(.*", ""); - String expectedMessagePart = format("(%1$s.*not (yet )?supported)|((?i)unsupported.*%1$s)|((?i)not supported.*%1$s)", Pattern.quote(typeNameBase)); assertThatThrownBy(setup::run) - .hasMessageFindingMatch(expectedMessagePart) - .satisfies(e -> assertThat(getTrinoExceptionCause(e)).hasMessageFindingMatch(expectedMessagePart)); + .satisfies(exception -> verifyUnsupportedTypeException(exception, trinoTypeName)); return; } setup.run(); @@ -2958,6 +2956,69 @@ private List testCaseSensitiveDataMappingData() .build(); } + /** + * A regression test for row (struct) dereference pushdown edge case, with duplicate expressions. + * See https://github.com/trinodb/trino/issues/11559 and https://github.com/trinodb/trino/issues/11560. + */ + @Test + public void testPotentialDuplicateDereferencePushdown() + { + skipTestUnless(hasBehavior(SUPPORTS_CREATE_TABLE_WITH_DATA)); + + String tableName = "test_dup_deref_" + randomTableSuffix(); + String createTable = "CREATE TABLE " + tableName + " AS SELECT CAST(ROW('abc', 1) AS row(a varchar, b bigint)) r"; + if (!hasBehavior(SUPPORTS_ROW_TYPE)) { + try { + assertUpdate(createTable); + } + catch (Exception expected) { + verifyUnsupportedTypeException(expected, "row(a varchar, b bigint)"); + return; + } + assertUpdate("DROP TABLE " + tableName); + fail("Expected create table failure"); + } + + assertUpdate(createTable, 1); + try { + assertThat(query("SELECT r, r.b + 2 FROM " + tableName)) + .matches("SELECT CAST(ROW('abc', 1) AS ROW(a varchar, b bigint)), BIGINT '3'"); + + assertThat(query("SELECT r[1], r[2], r.b + 2 FROM " + tableName)) + .matches("VALUES (VARCHAR 'abc', BIGINT '1', BIGINT '3')"); + + assertThat(query("SELECT r[2], r.b + 2 FROM " + tableName)) + .matches("VALUES (BIGINT '1', BIGINT '3')"); + + assertThat(query("SELECT r.b, r.b + 2 FROM " + tableName)) + .matches("VALUES (BIGINT '1', BIGINT '3')"); + + assertThat(query("SELECT r, r.a LIKE '%c' FROM " + tableName)) + .matches("SELECT CAST(ROW('abc', 1) AS ROW(a varchar, b bigint)), true"); + + assertThat(query("SELECT r[1], r[2], r.a LIKE '%c' FROM " + tableName)) + .matches("VALUES (VARCHAR 'abc', BIGINT '1', true)"); + + assertThat(query("SELECT r[1], r.a LIKE '%c' FROM " + tableName)) + .matches("VALUES (VARCHAR 'abc', true)"); + + assertThat(query("SELECT r.a, r.a LIKE '%c' FROM " + tableName)) + .matches("VALUES (VARCHAR 'abc', true)"); + } + finally { + assertUpdate("DROP TABLE " + tableName); + } + } + + private void verifyUnsupportedTypeException(Throwable exception, String trinoTypeName) + { + String typeNameBase = trinoTypeName.replaceFirst("\\(.*", ""); + String expectedMessagePart = format("(%1$s.*not (yet )?supported)|((?i)unsupported.*%1$s)|((?i)not supported.*%1$s)", Pattern.quote(typeNameBase)); + assertThat(exception) + .hasMessageFindingMatch(expectedMessagePart) + .satisfies(e -> assertThat(getTrinoExceptionCause(e)).hasMessageFindingMatch(expectedMessagePart)); + } + @Test(dataProvider = "testColumnNameDataProvider") public void testMaterializedViewColumnName(String columnName) { diff --git a/testing/trino-testing/src/main/java/io/trino/testing/TestingConnectorBehavior.java b/testing/trino-testing/src/main/java/io/trino/testing/TestingConnectorBehavior.java index ec745828f456..26732cdccf7a 100644 --- a/testing/trino-testing/src/main/java/io/trino/testing/TestingConnectorBehavior.java +++ b/testing/trino-testing/src/main/java/io/trino/testing/TestingConnectorBehavior.java @@ -81,6 +81,7 @@ public enum TestingConnectorBehavior SUPPORTS_TRUNCATE(false), SUPPORTS_ARRAY, + SUPPORTS_ROW_TYPE, SUPPORTS_NEGATIVE_DATE, SUPPORTS_CANCELLATION(false), diff --git a/testing/trino-tests/src/test/java/io/trino/tests/tpch/TestTpchConnectorTest.java b/testing/trino-tests/src/test/java/io/trino/tests/tpch/TestTpchConnectorTest.java index 64d11e6ae66f..6adb6e924874 100644 --- a/testing/trino-tests/src/test/java/io/trino/tests/tpch/TestTpchConnectorTest.java +++ b/testing/trino-tests/src/test/java/io/trino/tests/tpch/TestTpchConnectorTest.java @@ -78,6 +78,9 @@ protected boolean hasBehavior(TestingConnectorBehavior connectorBehavior) case SUPPORTS_ARRAY: return false; + case SUPPORTS_ROW_TYPE: + return false; + default: return super.hasBehavior(connectorBehavior); }