Skip to content

Trino fails when PostgreSQL table has a decimal/numeric column with negative scale #28388

@findepi

Description

@findepi

PostgreSQL connector attempts to support PostgreSQL decimal/numeric columns with negative scale

precision = columnSize + max(-decimalDigits, 0); // Map decimal(p, -s) (negative scale) to decimal(p+s, 0).

However, it doesn't appear to work.

repro steps

TestPostgreSqlTypeMapping + postgres:18 image +

SqlDataTypeTest.create()
        .addRoundTrip("decimal(9, -7)", "1234567890000000", DecimalType.createDecimalType(16, 0), "DECIMAL '1234567890000000'")
        .execute(getQueryRunner(), postgresCreateAndInsert("test_decimal_negative_scale"));
2026-02-20T12:19:22.037-0600	INFO	ForkJoinPool-1-worker-2	io.airlift.http.server.HttpServer	Server testing-trino-f061a8c6-88b7-445c-aa99-a66f1a243182 shutdown complete
2026-02-20T12:19:22.044-0600	INFO	ForkJoinPool-1-worker-2	io.airlift.http.server.HttpServer	Server testing-trino-9c4357cf-9e4d-439d-b535-492789bde004 shutdown complete
2026-02-20T12:19:22.047-0600	INFO	ForkJoinPool-1-worker-2	io.airlift.http.server.HttpServer	Server testing-trino-f6920c75-81e9-476f-9451-7be183745894 shutdown complete

io.trino.testing.QueryFailedException: DECIMAL scale must be in range [0, precision (9)]: 2041

	at io.trino.testing.AbstractTestingTrinoClient.execute(AbstractTestingTrinoClient.java:138)
	at io.trino.testing.DistributedQueryRunner.executeInternal(DistributedQueryRunner.java:591)
	at io.trino.testing.DistributedQueryRunner.execute(DistributedQueryRunner.java:574)
	at io.trino.sql.query.QueryAssertions$QueryAssert.lambda$new$1(QueryAssertions.java:318)
	at com.google.common.base.Suppliers$NonSerializableMemoizingSupplier.get(Suppliers.java:201)
	at io.trino.sql.query.QueryAssertions$QueryAssert.result(QueryAssertions.java:437)
	at io.trino.testing.datatype.SqlDataTypeTest.verifySelect(SqlDataTypeTest.java:102)
	at io.trino.testing.datatype.SqlDataTypeTest.execute(SqlDataTypeTest.java:90)
	at io.trino.testing.datatype.SqlDataTypeTest.execute(SqlDataTypeTest.java:83)
	at io.trino.plugin.postgresql.BasePostgreSqlTypeMappingTest.testPostgreSqlDecimalNegativeScale(BasePostgreSqlTypeMappingTest.java:157)
	at java.base/java.lang.reflect.Method.invoke(Method.java:565)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:511)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.tryRemoveAndExec(ForkJoinPool.java:1490)
	at java.base/java.util.concurrent.ForkJoinPool.helpJoin(ForkJoinPool.java:2248)
	at java.base/java.util.concurrent.ForkJoinTask.awaitDone(ForkJoinTask.java:499)
	at java.base/java.util.concurrent.ForkJoinTask.join(ForkJoinTask.java:666)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:511)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1450)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:2019)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:187)
	Suppressed: java.lang.Exception: SQL: SELECT * FROM test_byteagjpy7vequ0
		at io.trino.testing.DistributedQueryRunner.executeInternal(DistributedQueryRunner.java:598)
		... 18 more
Caused by: io.trino.spi.TrinoException: DECIMAL scale must be in range [0, precision (9)]: 2041
	at io.trino.spi.type.DecimalType.createDecimalType(DecimalType.java:44)
	at io.trino.plugin.postgresql.PostgreSqlClient.toColumnMapping(PostgreSqlClient.java:642)
	at io.trino.plugin.postgresql.PostgreSqlClient.getColumns(PostgreSqlClient.java:490)
	at io.trino.plugin.jdbc.ForwardingJdbcClient.getColumns(ForwardingJdbcClient.java:112)
	at io.trino.plugin.jdbc.jmx.StatisticsAwareJdbcClient.lambda$getColumns$0(StatisticsAwareJdbcClient.java:134)
	at io.trino.plugin.jdbc.jmx.JdbcApiStats.wrap(JdbcApiStats.java:34)
	at io.trino.plugin.jdbc.jmx.StatisticsAwareJdbcClient.getColumns(StatisticsAwareJdbcClient.java:134)
	at io.trino.plugin.jdbc.RetryingJdbcClient.lambda$getColumns$0(RetryingJdbcClient.java:109)
	at dev.failsafe.Functions.lambda$toCtxSupplier$11(Functions.java:243)
	at dev.failsafe.Functions.lambda$get$0(Functions.java:46)
	at dev.failsafe.internal.RetryPolicyExecutor.lambda$apply$0(RetryPolicyExecutor.java:74)
	at dev.failsafe.SyncExecutionImpl.executeSync(SyncExecutionImpl.java:187)
	at dev.failsafe.FailsafeExecutor.call(FailsafeExecutor.java:376)
	at dev.failsafe.FailsafeExecutor.get(FailsafeExecutor.java:112)
	at io.trino.plugin.jdbc.RetryingModule.retry(RetryingModule.java:67)
	at io.trino.plugin.jdbc.RetryingJdbcClient.getColumns(RetryingJdbcClient.java:109)
	at io.trino.plugin.jdbc.CachingJdbcClient.lambda$getColumns$0(CachingJdbcClient.java:186)
	at io.trino.cache.EmptyCache.get(EmptyCache.java:95)
	at io.trino.plugin.jdbc.CachingJdbcClient.get(CachingJdbcClient.java:835)
	at io.trino.plugin.jdbc.CachingJdbcClient.getColumns(CachingJdbcClient.java:186)
	at io.trino.plugin.jdbc.CachingJdbcClient.lambda$getColumns$0(CachingJdbcClient.java:186)
	at com.google.common.cache.LocalCache$LocalManualCache$1.load(LocalCache.java:4859)
	at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3556)
	at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2307)
	at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2180)
	at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2071)
	at com.google.common.cache.LocalCache.get(LocalCache.java:3985)
	at com.google.common.cache.LocalCache$LocalManualCache.get(LocalCache.java:4854)
	at io.trino.cache.EvictableCache.get(EvictableCache.java:120)
	at io.trino.plugin.jdbc.CachingJdbcClient.get(CachingJdbcClient.java:835)
	at io.trino.plugin.jdbc.CachingJdbcClient.getColumns(CachingJdbcClient.java:186)
	at io.trino.plugin.jdbc.DefaultJdbcMetadata.getTableSchema(DefaultJdbcMetadata.java:1068)
	at io.trino.plugin.base.classloader.ClassLoaderSafeConnectorMetadata.getTableSchema(ClassLoaderSafeConnectorMetadata.java:265)
	at io.trino.tracing.TracingConnectorMetadata.getTableSchema(TracingConnectorMetadata.java:233)
	at io.trino.metadata.MetadataManager.getTableSchema(MetadataManager.java:487)
	at io.trino.tracing.TracingMetadata.getTableSchema(TracingMetadata.java:310)
	at io.trino.sql.analyzer.StatementAnalyzer$Visitor.visitTable(StatementAnalyzer.java:2345)
	at io.trino.sql.analyzer.StatementAnalyzer$Visitor.visitTable(StatementAnalyzer.java:534)
	at io.trino.sql.tree.Table.accept(Table.java:70)
	at io.trino.sql.tree.AstVisitor.process(AstVisitor.java:27)
	at io.trino.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:553)
	at io.trino.sql.analyzer.StatementAnalyzer$Visitor.analyzeFrom(StatementAnalyzer.java:5107)
	at io.trino.sql.analyzer.StatementAnalyzer$Visitor.visitQuerySpecification(StatementAnalyzer.java:3180)
	at io.trino.sql.analyzer.StatementAnalyzer$Visitor.visitQuerySpecification(StatementAnalyzer.java:534)
	at io.trino.sql.tree.QuerySpecification.accept(QuerySpecification.java:155)
	at io.trino.sql.tree.AstVisitor.process(AstVisitor.java:27)
	at io.trino.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:553)
	at io.trino.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:561)
	at io.trino.sql.analyzer.StatementAnalyzer$Visitor.visitQuery(StatementAnalyzer.java:1607)
	at io.trino.sql.analyzer.StatementAnalyzer$Visitor.visitQuery(StatementAnalyzer.java:534)
	at io.trino.sql.tree.Query.accept(Query.java:130)
	at io.trino.sql.tree.AstVisitor.process(AstVisitor.java:27)
	at io.trino.sql.analyzer.StatementAnalyzer$Visitor.process(StatementAnalyzer.java:553)
	at io.trino.sql.analyzer.StatementAnalyzer.analyze(StatementAnalyzer.java:513)
	at io.trino.sql.analyzer.StatementAnalyzer.analyze(StatementAnalyzer.java:502)
	at io.trino.sql.analyzer.Analyzer.analyze(Analyzer.java:98)
	at io.trino.sql.analyzer.Analyzer.analyze(Analyzer.java:87)
	at io.trino.execution.SqlQueryExecution.analyze(SqlQueryExecution.java:288)
	at io.trino.execution.SqlQueryExecution.<init>(SqlQueryExecution.java:222)
	at io.trino.execution.SqlQueryExecution$SqlQueryExecutionFactory.createQueryExecution(SqlQueryExecution.java:892)
	at io.trino.dispatcher.LocalDispatchQueryFactory.lambda$createDispatchQuery$0(LocalDispatchQueryFactory.java:163)
	at io.trino.$gen.Trino_testversion____20260220_181918_1.call(Unknown Source)
	at com.google.common.util.concurrent.TrustedListenableFutureTask$TrustedFutureInterruptibleTask.runInterruptibly(TrustedListenableFutureTask.java:128)
	at com.google.common.util.concurrent.InterruptibleTask.run(InterruptibleTask.java:74)
	at com.google.common.util.concurrent.TrustedListenableFutureTask.run(TrustedListenableFutureTask.java:80)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)
	at java.base/java.lang.Thread.run(Thread.java:1474)

Metadata

Metadata

Assignees

Labels

postgresqlPostgreSQL connector

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions