Fix some column type definitions in dialects regarding their maximum capacities. Allow the dialect to resolve the length based on type code, type name, precision, scale and display size. Fix some dialect related issues with tests. Fix untyped null parameter binding issues

This commit is contained in:
Christian Beikov 2021-09-29 18:53:37 +02:00
parent 7fd3706a18
commit d8b984ed7f
35 changed files with 448 additions and 63 deletions

View File

@ -107,6 +107,7 @@ public class CUBRIDDialect extends Dialect {
@Override
public JdbcTypeDescriptor resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
@ -114,7 +115,13 @@ public class CUBRIDDialect extends Dialect {
if ( jdbcTypeCode == Types.BIT ) {
return jdbcTypeDescriptorRegistry.getDescriptor( Types.BOOLEAN );
}
return super.resolveSqlTypeDescriptor( jdbcTypeCode, precision, scale, jdbcTypeDescriptorRegistry );
return super.resolveSqlTypeDescriptor(
columnTypeName,
jdbcTypeCode,
precision,
scale,
jdbcTypeDescriptorRegistry
);
}
@Override

View File

@ -89,6 +89,7 @@ public class CacheDialect extends Dialect {
@Override
public JdbcTypeDescriptor resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
@ -96,7 +97,13 @@ public class CacheDialect extends Dialect {
if ( jdbcTypeCode == Types.BIT ) {
return jdbcTypeDescriptorRegistry.getDescriptor( Types.BOOLEAN );
}
return super.resolveSqlTypeDescriptor( jdbcTypeCode, precision, scale, jdbcTypeDescriptorRegistry );
return super.resolveSqlTypeDescriptor(
columnTypeName,
jdbcTypeCode,
precision,
scale,
jdbcTypeDescriptorRegistry
);
}
@Override

View File

@ -165,6 +165,7 @@ public class FirebirdDialect extends Dialect {
@Override
public JdbcTypeDescriptor resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
@ -172,7 +173,13 @@ public class FirebirdDialect extends Dialect {
if ( jdbcTypeCode == Types.BIT ) {
return jdbcTypeDescriptorRegistry.getDescriptor( Types.BOOLEAN );
}
return super.resolveSqlTypeDescriptor( jdbcTypeCode, precision, scale, jdbcTypeDescriptorRegistry );
return super.resolveSqlTypeDescriptor(
columnTypeName,
jdbcTypeCode,
precision,
scale,
jdbcTypeDescriptorRegistry
);
}
@Override

View File

@ -174,6 +174,7 @@ public class IngresDialect extends Dialect {
@Override
public JdbcTypeDescriptor resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
@ -181,7 +182,13 @@ public class IngresDialect extends Dialect {
if ( jdbcTypeCode == Types.BIT ) {
return jdbcTypeDescriptorRegistry.getDescriptor( Types.BOOLEAN );
}
return super.resolveSqlTypeDescriptor( jdbcTypeCode, precision, scale, jdbcTypeDescriptorRegistry );
return super.resolveSqlTypeDescriptor(
columnTypeName,
jdbcTypeCode,
precision,
scale,
jdbcTypeDescriptorRegistry
);
}
@Override

View File

@ -67,6 +67,7 @@ public class MaxDBDialect extends Dialect {
@Override
public JdbcTypeDescriptor resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
@ -78,7 +79,13 @@ public class MaxDBDialect extends Dialect {
return jdbcTypeDescriptorRegistry.getDescriptor( Types.BIGINT );
}
}
return super.resolveSqlTypeDescriptor( jdbcTypeCode, precision, scale, jdbcTypeDescriptorRegistry );
return super.resolveSqlTypeDescriptor(
columnTypeName,
jdbcTypeCode,
precision,
scale,
jdbcTypeDescriptorRegistry
);
}
@Override

View File

@ -114,6 +114,7 @@ public class RDMSOS2200Dialect extends Dialect {
@Override
public JdbcTypeDescriptor resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
@ -121,7 +122,13 @@ public class RDMSOS2200Dialect extends Dialect {
if ( jdbcTypeCode == Types.BIT ) {
return jdbcTypeDescriptorRegistry.getDescriptor( Types.BOOLEAN );
}
return super.resolveSqlTypeDescriptor( jdbcTypeCode, precision, scale, jdbcTypeDescriptorRegistry );
return super.resolveSqlTypeDescriptor(
columnTypeName,
jdbcTypeCode,
precision,
scale,
jdbcTypeDescriptorRegistry
);
}
@Override

View File

@ -126,7 +126,7 @@ public class TeradataDialect extends Dialect {
@Override
public JdbcTypeDescriptor resolveSqlTypeDescriptor(
int jdbcTypeCode,
String columnTypeName, int jdbcTypeCode,
int precision,
int scale,
JdbcTypeDescriptorRegistry jdbcTypeDescriptorRegistry) {
@ -139,7 +139,13 @@ public class TeradataDialect extends Dialect {
return jdbcTypeDescriptorRegistry.getDescriptor( Types.BIGINT );
}
}
return super.resolveSqlTypeDescriptor( jdbcTypeCode, precision, scale, jdbcTypeDescriptorRegistry );
return super.resolveSqlTypeDescriptor(
columnTypeName,
jdbcTypeCode,
precision,
scale,
jdbcTypeDescriptorRegistry
);
}
@Override

View File

@ -102,6 +102,7 @@ public class TimesTenDialect extends Dialect {
@Override
public JdbcTypeDescriptor resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
@ -109,7 +110,13 @@ public class TimesTenDialect extends Dialect {
if ( jdbcTypeCode == Types.BIT ) {
return jdbcTypeDescriptorRegistry.getDescriptor( Types.BOOLEAN );
}
return super.resolveSqlTypeDescriptor( jdbcTypeCode, precision, scale, jdbcTypeDescriptorRegistry );
return super.resolveSqlTypeDescriptor(
columnTypeName,
jdbcTypeCode,
precision,
scale,
jdbcTypeDescriptorRegistry
);
}
@Override

View File

@ -71,6 +71,7 @@ public abstract class AbstractTransactSQLDialect extends Dialect {
@Override
public JdbcTypeDescriptor resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
@ -78,7 +79,13 @@ public abstract class AbstractTransactSQLDialect extends Dialect {
if ( jdbcTypeCode == Types.BIT ) {
return jdbcTypeDescriptorRegistry.getDescriptor( Types.BOOLEAN );
}
return super.resolveSqlTypeDescriptor( jdbcTypeCode, precision, scale, jdbcTypeDescriptorRegistry );
return super.resolveSqlTypeDescriptor(
columnTypeName,
jdbcTypeCode,
precision,
scale,
jdbcTypeDescriptorRegistry
);
}
@Override

View File

@ -7,6 +7,7 @@
package org.hibernate.dialect;
import org.hibernate.LockOptions;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.query.NullPrecedence;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
@ -32,6 +33,7 @@ import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.mutation.internal.cte.CteStrategy;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
@ -40,6 +42,7 @@ import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorDB2DatabaseImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.jdbc.*;
@ -85,8 +88,8 @@ public class DB2Dialect extends Dialect {
registerColumnType( Types.TINYINT, "smallint" ); //no tinyint
//HHH-12827: map them both to the same type to
// avoid problems with schema update
//HHH-12827: map them both to the same type to avoid problems with schema update
//Note that 31 is the maximum precision DB2 supports
// registerColumnType( Types.DECIMAL, "decimal($p,$s)" );
registerColumnType( Types.NUMERIC, "decimal($p,$s)" );
@ -106,7 +109,8 @@ public class DB2Dialect extends Dialect {
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp($p)" );
registerColumnType( Types.TIME_WITH_TIMEZONE, "time" );
registerColumnType( Types.LONGVARCHAR, "long varchar" );
// The long varchar data type was deprecated in DB2 and shouldn't be used anymore
registerColumnType( Types.LONGVARCHAR, "clob($l)" );
//not keywords, at least not in DB2 11,
//but perhaps they were in older versions?
@ -570,6 +574,24 @@ public class DB2Dialect extends Dialect {
}
}
@Override
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes( typeContributions, serviceRegistry );
// DB2 requires a custom binder for binding untyped nulls that resolves the type through the statement
typeContributions.contributeJdbcTypeDescriptor( ObjectNullResolvingJdbcTypeDescriptor.INSTANCE );
// Until we remove StandardBasicTypes, we have to keep this
typeContributions.contributeType(
new JavaObjectType(
ObjectNullResolvingJdbcTypeDescriptor.INSTANCE,
typeContributions.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.getDescriptor( Object.class )
)
);
}
@Override
public String formatBinaryLiteral(byte[] bytes) {
return "BX'" + StandardBasicTypes.BINARY.toString( bytes ) + "'";

View File

@ -23,9 +23,7 @@ import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.NullnessLiteral;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.insert.InsertStatement;

View File

@ -9,6 +9,7 @@ package org.hibernate.dialect;
import org.hibernate.HibernateException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.DerbyConcatFunction;
@ -41,6 +42,7 @@ import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy;
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.CaseFragment;
import org.hibernate.sql.DerbyCaseFragment;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
@ -52,9 +54,11 @@ import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorDerbyDatabaseImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.jdbc.DecimalTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ObjectNullResolvingJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.SmallIntTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.TimestampTypeDescriptor;
@ -108,14 +112,16 @@ public class DerbyDialect extends Dialect {
registerColumnType( Types.TINYINT, "smallint" ); //no tinyint
registerColumnType( Types.CHAR, 254, "char($l)" );
//HHH-12827: map them both to the same type to
// avoid problems with schema update
//HHH-12827: map them both to the same type to avoid problems with schema update
//Note that 31 is the maximum precision Derby supports
// registerColumnType( Types.DECIMAL, "decimal($p,$s)" );
registerColumnType( Types.NUMERIC, "decimal($p,$s)" );
registerColumnType( Types.BINARY, "varchar($l) for bit data" );
registerColumnType( Types.BINARY, 254, "char($l) for bit data" );
registerColumnType( Types.VARBINARY, "varchar($l) for bit data" );
registerColumnType( Types.BINARY, 32672, "varchar($l) for bit data" );
registerColumnType( Types.BINARY, "long varchar for bit data" );
registerColumnType( Types.VARBINARY, 32672, "varchar($l) for bit data" );
registerColumnType( Types.VARBINARY, "long varchar for bit data" );
registerColumnType( Types.BLOB, "blob($l)" );
registerColumnType( Types.CLOB, "clob($l)" );
@ -539,6 +545,24 @@ public class DerbyDialect extends Dialect {
}
}
@Override
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes( typeContributions, serviceRegistry );
// Derby requires a custom binder for binding untyped nulls that resolves the type through the statement
typeContributions.contributeJdbcTypeDescriptor( ObjectNullResolvingJdbcTypeDescriptor.INSTANCE );
// Until we remove StandardBasicTypes, we have to keep this
typeContributions.contributeType(
new JavaObjectType(
ObjectNullResolvingJdbcTypeDescriptor.INSTANCE,
typeContributions.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.getDescriptor( Object.class )
)
);
}
@Override
public String getNotExpression( String expression ) {
return "not (" + expression + ")";

View File

@ -247,6 +247,7 @@ public abstract class Dialect implements ConversionContext {
}
public JdbcTypeDescriptor resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
@ -254,6 +255,22 @@ public abstract class Dialect implements ConversionContext {
return jdbcTypeDescriptorRegistry.getDescriptor( jdbcTypeCode );
}
public int resolveSqlTypeLength(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
int displaySize) {
// It seems MariaDB/MySQL return the precision in bytes depending on the charset,
// so to detect whether we have a single character here, we check the display size
if ( jdbcTypeCode == Types.CHAR && precision <= 4 ) {
return displaySize;
}
else {
return precision;
}
}
/**
* Useful conversion for databases which represent the
* precision of a float(p) using p expressed in decimal

View File

@ -17,6 +17,7 @@ import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.CastType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
@ -92,6 +93,26 @@ public class MariaDBDialect extends MySQLDialect {
};
}
@Override
public String castPattern(CastType from, CastType to) {
if ( to == CastType.INTEGER_BOOLEAN ) {
switch ( from ) {
case STRING:
case INTEGER:
case LONG:
case YN_BOOLEAN:
case TF_BOOLEAN:
case BOOLEAN:
break;
default:
// MariaDB doesn't support casting to bit
return "abs(sign(?1))";
}
}
return super.castPattern( from, to );
}
@Override
public boolean supportsRowValueConstructorSyntaxInInList() {
return true;
}

View File

@ -57,7 +57,6 @@ import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
@ -295,6 +294,7 @@ public class MySQLDialect extends Dialect {
@Override
public JdbcTypeDescriptor resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
@ -302,7 +302,13 @@ public class MySQLDialect extends Dialect {
if ( jdbcTypeCode == Types.BIT ) {
return jdbcTypeDescriptorRegistry.getDescriptor( Types.BOOLEAN );
}
return super.resolveSqlTypeDescriptor( jdbcTypeCode, precision, scale, jdbcTypeDescriptorRegistry );
return super.resolveSqlTypeDescriptor(
columnTypeName,
jdbcTypeCode,
precision,
scale,
jdbcTypeDescriptorRegistry
);
}
@Override

View File

@ -56,9 +56,13 @@ import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorOracleDatabaseImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.NullType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.jdbc.BlobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.NullJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ObjectNullAsNullTypeJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import java.sql.CallableStatement;
@ -536,6 +540,10 @@ public class OracleDialect extends Dialect {
registerColumnType( Types.TINYINT, "number(3,0)" );
registerColumnType( Types.INTEGER, "number(10,0)" );
// Oracle has DOUBLE semantics for the REAL type, so we map it to float(24)
registerColumnType( Types.REAL, "float(24)" );
// // Note that 38 is the maximum precision Oracle supports
registerColumnType( Types.NUMERIC, "number($p,$s)" );
registerColumnType( Types.DECIMAL, "number($p,$s)" );
}
@ -593,6 +601,7 @@ public class OracleDialect extends Dialect {
@Override
public JdbcTypeDescriptor resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
@ -600,6 +609,13 @@ public class OracleDialect extends Dialect {
// This is the reverse of what registerNumericTypeMappings registers
switch ( jdbcTypeCode ) {
case Types.NUMERIC:
// For some reason, the Oracle JDBC driver reports floats as numerics with scale -127
if ( scale == -127 ) {
if ( precision <= getFloatPrecision() ) {
return jdbcTypeDescriptorRegistry.getDescriptor( Types.FLOAT );
}
return jdbcTypeDescriptorRegistry.getDescriptor( Types.DOUBLE );
}
case Types.DECIMAL:
if ( scale == 0 ) {
switch ( precision ) {
@ -616,7 +632,13 @@ public class OracleDialect extends Dialect {
}
}
}
return super.resolveSqlTypeDescriptor( jdbcTypeCode, precision, scale, jdbcTypeDescriptorRegistry );
return super.resolveSqlTypeDescriptor(
columnTypeName,
jdbcTypeCode,
precision,
scale,
jdbcTypeDescriptorRegistry
);
}
/**
@ -648,6 +670,28 @@ public class OracleDialect extends Dialect {
typeContributions.contributeJdbcTypeDescriptor( descriptor );
}
// Oracle requires a custom binder for binding untyped nulls with the NULL type
typeContributions.contributeJdbcTypeDescriptor( NullJdbcTypeDescriptor.INSTANCE );
typeContributions.contributeJdbcTypeDescriptor( ObjectNullAsNullTypeJdbcTypeDescriptor.INSTANCE );
// Until we remove StandardBasicTypes, we have to keep this
typeContributions.contributeType(
new NullType(
NullJdbcTypeDescriptor.INSTANCE,
typeContributions.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.getDescriptor( Object.class )
)
);
typeContributions.contributeType(
new JavaObjectType(
ObjectNullAsNullTypeJdbcTypeDescriptor.INSTANCE,
typeContributions.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.getDescriptor( Object.class )
)
);
}
@Override

View File

@ -57,11 +57,13 @@ import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.PostgresUUIDType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.jdbc.BlobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ClobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcTypeDescriptor;
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
import static org.hibernate.query.TemporalUnit.*;
@ -903,5 +905,18 @@ public class PostgreSQLDialect extends Dialect {
// HHH-9562
typeContributions.contributeType( PostgresUUIDType.INSTANCE );
}
// PostgreSQL requires a custom binder for binding untyped nulls as VARBINARY
typeContributions.contributeJdbcTypeDescriptor( ObjectNullAsBinaryTypeJdbcTypeDescriptor.INSTANCE );
// Until we remove StandardBasicTypes, we have to keep this
typeContributions.contributeType(
new JavaObjectType(
ObjectNullAsBinaryTypeJdbcTypeDescriptor.INSTANCE,
typeContributions.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.getDescriptor( Object.class )
)
);
}
}

View File

@ -148,6 +148,11 @@ public class SybaseASEDialect extends SybaseDialect {
return ansiNull;
}
@Override
public int getFloatPrecision() {
return 15;
}
@Override
public int getDoublePrecision() {
return 48;
@ -195,6 +200,22 @@ public class SybaseASEDialect extends SybaseDialect {
}
}
@Override
public int resolveSqlTypeLength(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
int displaySize) {
// Sybase ASE reports the "actual" precision in the display size
switch ( jdbcTypeCode ) {
case Types.REAL:
case Types.DOUBLE:
return displaySize;
}
return super.resolveSqlTypeLength( columnTypeName, jdbcTypeCode, precision, scale, displaySize );
}
@Override
public String currentDate() {
return "current_date()";

View File

@ -23,9 +23,7 @@ import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.NullnessLiteral;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.from.TableGroup;
@ -222,12 +220,10 @@ public class SybaseASESqlAstTranslator<T extends JdbcOperation> extends Abstract
// The ansinull setting only matters if using a parameter or literal and the eq operator according to the docs
// http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc32300.1570/html/sqlug/sqlug89.htm
boolean rhsNotNullPredicate =
lhs instanceof NullnessLiteral
|| lhs instanceof Literal
lhs instanceof Literal
|| isParameter( lhs );
boolean lhsNotNullPredicate =
rhs instanceof NullnessLiteral
|| rhs instanceof Literal
rhs instanceof Literal
|| isParameter( rhs );
if ( rhsNotNullPredicate || lhsNotNullPredicate ) {
lhs.accept( this );

View File

@ -37,10 +37,12 @@ import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.descriptor.jdbc.BlobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ClobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.NClobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ObjectNullAsNullTypeJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.SmallIntTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.TinyIntTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
@ -85,6 +87,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
@Override
public JdbcTypeDescriptor resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
@ -100,9 +103,16 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
return jdbcTypeDescriptorRegistry.getDescriptor( Types.SMALLINT );
}
}
return super.resolveSqlTypeDescriptor( jdbcTypeCode, precision, scale, jdbcTypeDescriptorRegistry );
return super.resolveSqlTypeDescriptor(
columnTypeName,
jdbcTypeCode,
precision,
scale,
jdbcTypeDescriptorRegistry
);
}
@Override
public JdbcTypeDescriptor remapSqlTypeDescriptor(JdbcTypeDescriptor jdbcTypeDescriptor) {
if ( jtdsDriver && TinyIntTypeDescriptor.INSTANCE == jdbcTypeDescriptor ) {
return SmallIntTypeDescriptor.INSTANCE;
@ -174,6 +184,19 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
);
typeContributions.contributeJdbcTypeDescriptor( ClobTypeDescriptor.CLOB_BINDING );
}
// Sybase requires a custom binder for binding untyped nulls with the NULL type
typeContributions.contributeJdbcTypeDescriptor( ObjectNullAsNullTypeJdbcTypeDescriptor.INSTANCE );
// Until we remove StandardBasicTypes, we have to keep this
typeContributions.contributeType(
new JavaObjectType(
ObjectNullAsNullTypeJdbcTypeDescriptor.INSTANCE,
typeContributions.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.getDescriptor( Object.class )
)
);
}
@Override

View File

@ -173,7 +173,13 @@ public class ParameterMetadataImpl implements ParameterMetadataImplementor {
if ( sqmParameters == null || sqmParameters.isEmpty() ) {
return null;
}
return sqmParameters.get( 0 ).getNodeType();
for ( SqmParameter sqmParameter : sqmParameters ) {
final AllowableParameterType nodeType = sqmParameter.getNodeType();
if ( nodeType != null ) {
return nodeType;
}
}
return null;
}
@Override

View File

@ -18,7 +18,6 @@ import org.hibernate.query.QueryParameter;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindingTypeResolver;
import org.hibernate.query.spi.QueryParameterBindingValidator;
import org.hibernate.type.NullType;
import org.hibernate.type.descriptor.java.CoercionException;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
@ -119,8 +118,7 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
}
if ( resolveJdbcTypeIfNecessary && bindType == null && value == null ) {
//noinspection unchecked
bindType = (AllowableParameterType<T>) NullType.INSTANCE;
bindType = getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( "null" );
}
bindValue( value );
}
@ -297,19 +295,24 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
}
@Override
public void setType(MappingModelExpressable type) {
public boolean setType(MappingModelExpressable type) {
this.type = type;
if ( bindType == null ) {
if ( bindType == null || bindType.getJavaType() == Object.class ) {
if ( type instanceof AllowableParameterType<?> ) {
final boolean changed = bindType != null && type != bindType;
this.bindType = (AllowableParameterType<T>) type;
return changed;
}
else if ( type instanceof BasicValuedMapping ) {
final JdbcMapping jdbcMapping = ( (BasicValuedMapping) type ).getJdbcMapping();
if ( jdbcMapping instanceof AllowableParameterType<?> ) {
final boolean changed = bindType != null && jdbcMapping != bindType;
this.bindType = (AllowableParameterType<T>) jdbcMapping;
return changed;
}
}
}
return false;
}
private void validate(T value) {

View File

@ -31,7 +31,6 @@ import jakarta.persistence.LockModeType;
import jakarta.persistence.NoResultException;
import jakarta.persistence.Parameter;
import jakarta.persistence.TemporalType;
import jakarta.persistence.TransactionRequiredException;
import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
@ -46,7 +45,6 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.EntityManagerMessageLogger;
import org.hibernate.internal.HEMLogging;
import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.jpa.QueryHints;
import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
@ -415,8 +413,8 @@ public abstract class AbstractQuery<R> implements QueryImplementor<R> {
if ( getCacheMode() != null ) {
putIfNotNull( hints, HINT_CACHE_MODE, getCacheMode() );
putIfNotNull( hints, JAKARTA_SHARED_CACHE_RETRIEVE_MODE, CacheModeHelper.interpretCacheRetrieveMode( getCacheMode() ) );
putIfNotNull( hints, JAKARTA_SHARED_CACHE_STORE_MODE, CacheModeHelper.interpretCacheStoreMode( getCacheMode() ) );
putIfNotNull( hints, JAKARTA_SHARED_CACHE_RETRIEVE_MODE, getQueryOptions().getCacheRetrieveMode() );
putIfNotNull( hints, JAKARTA_SHARED_CACHE_STORE_MODE, getQueryOptions().getCacheStoreMode() );
putIfNotNull( hints, JPA_SHARED_CACHE_RETRIEVE_MODE, getQueryOptions().getCacheRetrieveMode() );
putIfNotNull( hints, JPA_SHARED_CACHE_STORE_MODE, getQueryOptions().getCacheStoreMode() );
}

View File

@ -121,6 +121,7 @@ public interface QueryParameterBinding<T> {
* Sets the mapping model expressable for this parameter.
*
* @param type The mapping model expressable
* @return Whether the bind type was changed
*/
void setType(MappingModelExpressable<T> type);
boolean setType(MappingModelExpressable<T> type);
}

View File

@ -60,11 +60,13 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.EntityVersionMapping;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.SqlExpressable;
import org.hibernate.metamodel.mapping.ValueMapping;
import org.hibernate.metamodel.mapping.internal.EmbeddedCollectionPart;
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
@ -2935,7 +2937,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final QueryParameterImplementor<?> queryParameter = domainParameterXref.getQueryParameter( sqmParameter );
final QueryParameterBinding<?> binding = domainParameterBindings.getBinding( queryParameter );
binding.setType( valueMapping );
if ( binding.setType( valueMapping ) ) {
replaceJdbcParametersType(
sqmParameter,
domainParameterXref.getSqmParameters( queryParameter ),
valueMapping
);
}
return new SqmParameterInterpretation(
sqmParameter,
queryParameter,
@ -2945,6 +2953,32 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
);
}
private void replaceJdbcParametersType(
SqmParameter sourceSqmParameter,
List<SqmParameter> sqmParameters,
MappingModelExpressable<?> valueMapping) {
final JdbcMapping jdbcMapping = valueMapping.getJdbcMappings().get( 0 );
for ( SqmParameter<?> sqmParameter : sqmParameters ) {
if ( sqmParameter == sourceSqmParameter ) {
continue;
}
sqmParameterMappingModelTypes.put( sqmParameter, valueMapping );
final List<List<JdbcParameter>> jdbcParamsForSqmParameter = jdbcParamsBySqmParam.get( sqmParameter );
if ( jdbcParamsForSqmParameter != null ) {
for ( List<JdbcParameter> parameters : jdbcParamsForSqmParameter ) {
assert parameters.size() == 1;
final JdbcParameter jdbcParameter = parameters.get( 0 );
if ( ( (SqlExpressable) jdbcParameter ).getJdbcMapping() != valueMapping ) {
final JdbcParameter newJdbcParameter = new JdbcParameterImpl( jdbcMapping );
parameters.set( 0, newJdbcParameter );
jdbcParameters.getJdbcParameters().remove( jdbcParameter );
jdbcParameters.getJdbcParameters().add( newJdbcParameter );
}
}
}
}
}
protected Expression consumeSqmParameter(SqmParameter sqmParameter) {
if ( sqmParameter.allowMultiValuedBinding() ) {
final QueryParameterImplementor<?> domainParam = domainParameterXref.getQueryParameter( sqmParameter );
@ -2996,7 +3030,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final QueryParameterImplementor<?> queryParameter = domainParameterXref.getQueryParameter( sqmParameter );
final QueryParameterBinding<?> binding = domainParameterBindings.getBinding( queryParameter );
binding.setType( valueMapping );
if ( binding.setType( valueMapping ) ) {
replaceJdbcParametersType(
sqmParameter,
domainParameterXref.getSqmParameters( queryParameter ),
valueMapping
);
}
return new SqmParameterInterpretation(
sqmParameter,
queryParameter,

View File

@ -9,10 +9,10 @@ package org.hibernate.sql.results.jdbc.internal;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import javax.persistence.EnumType;
import jakarta.persistence.EnumType;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
@ -77,18 +77,22 @@ public interface ResultSetAccess extends JdbcValuesMetadata {
final JdbcServices jdbcServices = getFactory().getJdbcServices();
try {
final ResultSetMetaData metaData = getResultSet().getMetaData();
final String columnTypeName = metaData.getColumnTypeName( position );
final int columnType = metaData.getColumnType( position );
final int scale = metaData.getScale( position );
final int precision = metaData.getPrecision( position );
final int length;
if ( columnType == Types.CHAR && precision == 0 ) {
length = metaData.getColumnDisplaySize( position );
}
else {
length = precision;
}
final JdbcTypeDescriptor resolvedJdbcTypeDescriptor = jdbcServices.getDialect()
final int displaySize = metaData.getColumnDisplaySize( position );
final Dialect dialect = jdbcServices.getDialect();
final int length = dialect.resolveSqlTypeLength(
columnTypeName,
columnType,
precision,
scale,
displaySize
);
final JdbcTypeDescriptor resolvedJdbcTypeDescriptor = dialect
.resolveSqlTypeDescriptor(
columnTypeName,
columnType,
length,
scale,

View File

@ -24,4 +24,13 @@ public class NullType extends JavaObjectType {
public NullType() {
super( ObjectNullResolvingJdbcTypeDescriptor.INSTANCE, JavaObjectTypeDescriptor.INSTANCE );
}
public NullType(JdbcTypeDescriptor jdbcTypeDescriptor, JavaTypeDescriptor<Object> javaTypeDescriptor) {
super( jdbcTypeDescriptor, javaTypeDescriptor );
}
@Override
public String getName() {
return "null";
}
}

View File

@ -949,6 +949,13 @@ public final class StandardBasicTypes {
"object", Object.class.getName()
);
handle(
NullType.INSTANCE,
null,
basicTypeRegistry,
"null"
);
// todo (6.0) - ? how to handle DbTimestampType?
// DbTimestampType was really just a variant of TimestampType with overridden
// version (opt lock) support

View File

@ -12,6 +12,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
@ -56,6 +57,9 @@ public class FloatTypeDescriptor implements JdbcTypeDescriptor {
Integer length,
Integer scale,
TypeConfiguration typeConfiguration) {
if ( length != null && length <= typeConfiguration.getServiceRegistry().getService( JdbcServices.class ).getDialect().getFloatPrecision() ) {
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Float.class );
}
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Double.class );
}

View File

@ -0,0 +1,70 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.type.descriptor.jdbc;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* Descriptor for binding nulls with Types.NULL
*
* @author Christian Beikov
*/
public class NullJdbcTypeDescriptor implements JdbcTypeDescriptor {
/**
* Singleton access
*/
public static final NullJdbcTypeDescriptor INSTANCE = new NullJdbcTypeDescriptor();
@Override
public int getJdbcTypeCode() {
return Types.NULL;
}
@Override
public boolean canBeRemapped() {
return false;
}
@Override
public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) {
return null;
}
@Override
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicBinder<X>( javaTypeDescriptor, this ) {
@Override
protected void doBindNull(PreparedStatement st, int index, WrapperOptions options) throws SQLException {
st.setNull( index, Types.NULL );
}
@Override
protected void doBindNull(CallableStatement st, String name, WrapperOptions options) throws SQLException {
st.setNull( name, Types.NULL );
}
@Override
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) {
throw new UnsupportedOperationException( getClass().getName() + " should only be used to bind null!" );
}
@Override
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) {
throw new UnsupportedOperationException( getClass().getName() + " should only be used to bind null!" );
}
};
}
}

View File

@ -11,7 +11,7 @@ import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import javax.persistence.TypedQuery;
import jakarta.persistence.TypedQuery;
import org.hibernate.dialect.PostgreSQLDialect;

View File

@ -10,7 +10,7 @@ import jakarta.persistence.EntityManagerFactory;
import java.util.Arrays;
import org.hibernate.orm.test.jpa.TestingEntityManagerFactoryGenerator;
import org.hibernate.jpa.AvailableSettings;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.BaseUnitTest;

View File

@ -10,7 +10,7 @@ import jakarta.persistence.EntityManagerFactory;
import java.util.Arrays;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.jpa.test.TestingEntityManagerFactoryGenerator;
import org.hibernate.orm.test.jpa.TestingEntityManagerFactoryGenerator;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.BaseUnitTest;

View File

@ -47,13 +47,7 @@ public class ReadWriteExpressionChange extends BaseEnversJPAFunctionalTestCase {
em.getTransaction().begin();
List resultList = em.createNativeQuery( "select size_in_cm from t_staff_AUD where id =" + id ).getResultList();
Assert.assertEquals( 1, resultList.size() );
Double sizeInCm = null;
if ( getDialect() instanceof OracleDialect ) {
sizeInCm = ((BigDecimal) resultList.get( 0 )).doubleValue();
}
else {
sizeInCm = (Double) resultList.get( 0 );
}
Double sizeInCm = (Double) resultList.get( 0 );
em.getTransaction().commit();
Assert.assertEquals( HEIGHT_CENTIMETERS, sizeInCm.doubleValue(), 0.00000001 );
}

View File

@ -20,7 +20,7 @@ import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;