-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Disable incorrect character pushdown in PostgreSQL #7145
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,6 +33,7 @@ | |
import io.trino.plugin.jdbc.LongWriteFunction; | ||
import io.trino.plugin.jdbc.ObjectReadFunction; | ||
import io.trino.plugin.jdbc.ObjectWriteFunction; | ||
import io.trino.plugin.jdbc.PredicatePushdownController; | ||
import io.trino.plugin.jdbc.ReadFunction; | ||
import io.trino.plugin.jdbc.SliceReadFunction; | ||
import io.trino.plugin.jdbc.SliceWriteFunction; | ||
|
@@ -122,16 +123,16 @@ | |
import static io.trino.plugin.jdbc.DecimalSessionSessionProperties.getDecimalRoundingMode; | ||
import static io.trino.plugin.jdbc.JdbcErrorCode.JDBC_ERROR; | ||
import static io.trino.plugin.jdbc.PredicatePushdownController.DISABLE_PUSHDOWN; | ||
import static io.trino.plugin.jdbc.PredicatePushdownController.FULL_PUSHDOWN; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.bigintColumnMapping; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.bigintWriteFunction; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.booleanColumnMapping; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.booleanWriteFunction; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.charReadFunction; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.charWriteFunction; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.dateColumnMapping; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.dateWriteFunction; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.decimalColumnMapping; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.defaultCharColumnMapping; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.defaultVarcharColumnMapping; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.doubleColumnMapping; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.doubleWriteFunction; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.fromTrinoTimestamp; | ||
|
@@ -147,6 +148,7 @@ | |
import static io.trino.plugin.jdbc.StandardColumnMappings.tinyintWriteFunction; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.varbinaryColumnMapping; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.varbinaryWriteFunction; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.varcharReadFunction; | ||
import static io.trino.plugin.jdbc.StandardColumnMappings.varcharWriteFunction; | ||
import static io.trino.plugin.jdbc.TypeHandlingJdbcSessionProperties.getUnsupportedTypeHandling; | ||
import static io.trino.plugin.jdbc.UnsupportedTypeHandling.CONVERT_TO_VARCHAR; | ||
|
@@ -164,6 +166,7 @@ | |
import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED; | ||
import static io.trino.spi.type.BigintType.BIGINT; | ||
import static io.trino.spi.type.BooleanType.BOOLEAN; | ||
import static io.trino.spi.type.CharType.createCharType; | ||
import static io.trino.spi.type.DateTimeEncoding.packDateTimeWithZone; | ||
import static io.trino.spi.type.DateTimeEncoding.unpackMillisUtc; | ||
import static io.trino.spi.type.DateType.DATE; | ||
|
@@ -188,6 +191,8 @@ | |
import static io.trino.spi.type.TypeSignature.mapType; | ||
import static io.trino.spi.type.VarbinaryType.VARBINARY; | ||
import static io.trino.spi.type.VarcharType.VARCHAR; | ||
import static io.trino.spi.type.VarcharType.createUnboundedVarcharType; | ||
import static io.trino.spi.type.VarcharType.createVarcharType; | ||
import static java.lang.Math.max; | ||
import static java.lang.Math.min; | ||
import static java.lang.String.format; | ||
|
@@ -216,6 +221,22 @@ public class PostgreSqlClient | |
private final List<String> tableTypes; | ||
private final AggregateFunctionRewriter aggregateFunctionRewriter; | ||
|
||
private static final PredicatePushdownController POSTGRESQL_CHARACTER_PUSHDOWN = (session, domain) -> { | ||
checkArgument( | ||
domain.getType() instanceof VarcharType || domain.getType() instanceof CharType, | ||
"This PredicatePushdownController can be used only for chars and varchars"); | ||
|
||
if (domain.isOnlyNull() || | ||
// PostgreSQL is case sensitive by default | ||
domain.getValues().isDiscreteSet()) { | ||
return FULL_PUSHDOWN.apply(session, domain); | ||
} | ||
|
||
// PostgreSQL by default orders lowercase letters before uppercase, which is different from Trino | ||
// TODO We could still push the predicates down if we could inject a PostgreSQL-specific syntax for selecting a collation for given comparison. | ||
return DISABLE_PUSHDOWN.apply(session, domain); | ||
}; | ||
|
||
@Inject | ||
public PostgreSqlClient( | ||
BaseJdbcConfig config, | ||
|
@@ -455,14 +476,14 @@ public Optional<ColumnMapping> toColumnMapping(ConnectorSession session, Connect | |
} | ||
|
||
case Types.CHAR: | ||
return Optional.of(defaultCharColumnMapping(typeHandle.getRequiredColumnSize(), true)); | ||
return Optional.of(charColumnMapping(typeHandle.getRequiredColumnSize())); | ||
|
||
case Types.VARCHAR: | ||
if (!jdbcTypeName.equals("varchar")) { | ||
// This can be e.g. an ENUM | ||
return Optional.of(typedVarcharColumnMapping(jdbcTypeName)); | ||
} | ||
return Optional.of(defaultVarcharColumnMapping(typeHandle.getRequiredColumnSize(), true)); | ||
return Optional.of(varcharColumnMapping(typeHandle.getRequiredColumnSize())); | ||
|
||
case Types.BINARY: | ||
return Optional.of(varbinaryColumnMapping()); | ||
|
@@ -689,6 +710,31 @@ public boolean isLimitGuaranteed(ConnectorSession session) | |
return true; | ||
} | ||
|
||
private static ColumnMapping charColumnMapping(int charLength) | ||
{ | ||
if (charLength > CharType.MAX_LENGTH) { | ||
return varcharColumnMapping(charLength); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this still preserve the char semantics of padding values? There should be a test. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there is a test There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good catch. it doesn't correctly pad on write path and during predicate pushdown (this may or may not be relevant, depending on remote's coercions, need checking) it's pre-existing behavior though and applies to other connectors as well, see do you want to file an issue for this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #7152 - the title could be better though. |
||
} | ||
CharType charType = createCharType(charLength); | ||
return ColumnMapping.sliceMapping( | ||
charType, | ||
charReadFunction(charType), | ||
charWriteFunction(), | ||
POSTGRESQL_CHARACTER_PUSHDOWN); | ||
} | ||
|
||
private static ColumnMapping varcharColumnMapping(int varcharLength) | ||
{ | ||
VarcharType varcharType = varcharLength <= VarcharType.MAX_LENGTH | ||
? createVarcharType(varcharLength) | ||
: createUnboundedVarcharType(); | ||
return ColumnMapping.sliceMapping( | ||
varcharType, | ||
varcharReadFunction(varcharType), | ||
varcharWriteFunction(), | ||
POSTGRESQL_CHARACTER_PUSHDOWN); | ||
} | ||
|
||
private static ColumnMapping timeColumnMapping(int precision) | ||
{ | ||
verify(precision <= 6, "Unsupported precision: %s", precision); // PostgreSQL limit but also assumption within this method | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd put these two conditions on one line, with the comment inside the
if
block.Maybe also add a bit more to the comment explaining how
isDiscreteSet
is related to case sensitivity. The comment doesn't really clarify much right now. (Ideally, I thinkCASE_INSENSITIVE_CHARACTER_PUSHDOWN
would have a more detailed explanation of how that works, and then we could reference it here.)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I put the comment in between so it unambiguous what it refers to
point take on the issue how discrete sets translate to actual predicates, and indeed it applies to CASE_INSENSITIVE_CHARACTER_PUSHDOWN