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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,6 +7,7 @@
package org.hibernate.dialect; package org.hibernate.dialect;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.query.NullPrecedence; import org.hibernate.query.NullPrecedence;
import org.hibernate.cfg.Environment; import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory; 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.spi.QueryEngine;
import org.hibernate.query.sqm.mutation.internal.cte.CteStrategy; import org.hibernate.query.sqm.mutation.internal.cte.CteStrategy;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory; 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.SequenceInformationExtractorDB2DatabaseImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl; import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.jdbc.*; import org.hibernate.type.descriptor.jdbc.*;
@ -85,8 +88,8 @@ public class DB2Dialect extends Dialect {
registerColumnType( Types.TINYINT, "smallint" ); //no tinyint registerColumnType( Types.TINYINT, "smallint" ); //no tinyint
//HHH-12827: map them both to the same type to //HHH-12827: map them both to the same type to avoid problems with schema update
// avoid problems with schema update //Note that 31 is the maximum precision DB2 supports
// registerColumnType( Types.DECIMAL, "decimal($p,$s)" ); // registerColumnType( Types.DECIMAL, "decimal($p,$s)" );
registerColumnType( Types.NUMERIC, "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.TIMESTAMP_WITH_TIMEZONE, "timestamp($p)" );
registerColumnType( Types.TIME_WITH_TIMEZONE, "time" ); 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, //not keywords, at least not in DB2 11,
//but perhaps they were in older versions? //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 @Override
public String formatBinaryLiteral(byte[] bytes) { public String formatBinaryLiteral(byte[] bytes) {
return "BX'" + StandardBasicTypes.BINARY.toString( 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.CaseSimpleExpression;
import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression; 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.Literal;
import org.hibernate.sql.ast.tree.expression.NullnessLiteral;
import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization; import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.insert.InsertStatement; 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.HibernateException;
import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.boot.TempTableDdlTransactionHandling; import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.cfg.Environment; import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory; import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.DerbyConcatFunction; 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.LocalTemporaryTableStrategy;
import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter; import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.CaseFragment; import org.hibernate.sql.CaseFragment;
import org.hibernate.sql.DerbyCaseFragment; import org.hibernate.sql.DerbyCaseFragment;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode; 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.SequenceInformationExtractorDerbyDatabaseImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl; import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.jdbc.DecimalTypeDescriptor; import org.hibernate.type.descriptor.jdbc.DecimalTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor; 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.SmallIntTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.TimestampTypeDescriptor; import org.hibernate.type.descriptor.jdbc.TimestampTypeDescriptor;
@ -108,14 +112,16 @@ public class DerbyDialect extends Dialect {
registerColumnType( Types.TINYINT, "smallint" ); //no tinyint registerColumnType( Types.TINYINT, "smallint" ); //no tinyint
registerColumnType( Types.CHAR, 254, "char($l)" ); registerColumnType( Types.CHAR, 254, "char($l)" );
//HHH-12827: map them both to the same type to //HHH-12827: map them both to the same type to avoid problems with schema update
// avoid problems with schema update //Note that 31 is the maximum precision Derby supports
// registerColumnType( Types.DECIMAL, "decimal($p,$s)" ); // registerColumnType( Types.DECIMAL, "decimal($p,$s)" );
registerColumnType( Types.NUMERIC, "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.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.BLOB, "blob($l)" );
registerColumnType( Types.CLOB, "clob($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 @Override
public String getNotExpression( String expression ) { public String getNotExpression( String expression ) {
return "not (" + expression + ")"; return "not (" + expression + ")";

View File

@ -247,6 +247,7 @@ public abstract class Dialect implements ConversionContext {
} }
public JdbcTypeDescriptor resolveSqlTypeDescriptor( public JdbcTypeDescriptor resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode, int jdbcTypeCode,
int precision, int precision,
int scale, int scale,
@ -254,6 +255,22 @@ public abstract class Dialect implements ConversionContext {
return jdbcTypeDescriptorRegistry.getDescriptor( jdbcTypeCode ); 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 * Useful conversion for databases which represent the
* precision of a float(p) using p expressed in decimal * 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.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.CastType;
import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryEngine;
import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory; 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() { public boolean supportsRowValueConstructorSyntaxInInList() {
return true; return true;
} }

View File

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

View File

@ -56,9 +56,13 @@ import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation; import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorOracleDatabaseImpl; import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorOracleDatabaseImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; 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.StandardBasicTypes;
import org.hibernate.type.descriptor.jdbc.BlobTypeDescriptor; import org.hibernate.type.descriptor.jdbc.BlobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor; 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 org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import java.sql.CallableStatement; import java.sql.CallableStatement;
@ -536,6 +540,10 @@ public class OracleDialect extends Dialect {
registerColumnType( Types.TINYINT, "number(3,0)" ); registerColumnType( Types.TINYINT, "number(3,0)" );
registerColumnType( Types.INTEGER, "number(10,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.NUMERIC, "number($p,$s)" );
registerColumnType( Types.DECIMAL, "number($p,$s)" ); registerColumnType( Types.DECIMAL, "number($p,$s)" );
} }
@ -593,6 +601,7 @@ public class OracleDialect extends Dialect {
@Override @Override
public JdbcTypeDescriptor resolveSqlTypeDescriptor( public JdbcTypeDescriptor resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode, int jdbcTypeCode,
int precision, int precision,
int scale, int scale,
@ -600,6 +609,13 @@ public class OracleDialect extends Dialect {
// This is the reverse of what registerNumericTypeMappings registers // This is the reverse of what registerNumericTypeMappings registers
switch ( jdbcTypeCode ) { switch ( jdbcTypeCode ) {
case Types.NUMERIC: 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: case Types.DECIMAL:
if ( scale == 0 ) { if ( scale == 0 ) {
switch ( precision ) { 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 ); 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 @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.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement; import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation; import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.PostgresUUIDType; import org.hibernate.type.PostgresUUIDType;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.jdbc.BlobTypeDescriptor; import org.hibernate.type.descriptor.jdbc.BlobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ClobTypeDescriptor; import org.hibernate.type.descriptor.jdbc.ClobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor; 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.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
import static org.hibernate.query.TemporalUnit.*; import static org.hibernate.query.TemporalUnit.*;
@ -903,5 +905,18 @@ public class PostgreSQLDialect extends Dialect {
// HHH-9562 // HHH-9562
typeContributions.contributeType( PostgresUUIDType.INSTANCE ); 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; return ansiNull;
} }
@Override
public int getFloatPrecision() {
return 15;
}
@Override @Override
public int getDoublePrecision() { public int getDoublePrecision() {
return 48; 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 @Override
public String currentDate() { public String currentDate() {
return "current_date()"; 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.CaseSimpleExpression;
import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression; 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.Literal;
import org.hibernate.sql.ast.tree.expression.NullnessLiteral;
import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization; import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.from.TableGroup; 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 // 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 // http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc32300.1570/html/sqlug/sqlug89.htm
boolean rhsNotNullPredicate = boolean rhsNotNullPredicate =
lhs instanceof NullnessLiteral lhs instanceof Literal
|| lhs instanceof Literal
|| isParameter( lhs ); || isParameter( lhs );
boolean lhsNotNullPredicate = boolean lhsNotNullPredicate =
rhs instanceof NullnessLiteral rhs instanceof Literal
|| rhs instanceof Literal
|| isParameter( rhs ); || isParameter( rhs );
if ( rhsNotNullPredicate || lhsNotNullPredicate ) { if ( rhsNotNullPredicate || lhsNotNullPredicate ) {
lhs.accept( this ); 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.Statement;
import org.hibernate.sql.ast.tree.select.SelectStatement; import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.spi.JdbcOperation; 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.BlobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ClobTypeDescriptor; import org.hibernate.type.descriptor.jdbc.ClobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor; import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.NClobTypeDescriptor; 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.SmallIntTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.TinyIntTypeDescriptor; import org.hibernate.type.descriptor.jdbc.TinyIntTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
@ -85,6 +87,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
@Override @Override
public JdbcTypeDescriptor resolveSqlTypeDescriptor( public JdbcTypeDescriptor resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode, int jdbcTypeCode,
int precision, int precision,
int scale, int scale,
@ -100,9 +103,16 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
return jdbcTypeDescriptorRegistry.getDescriptor( Types.SMALLINT ); 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) { public JdbcTypeDescriptor remapSqlTypeDescriptor(JdbcTypeDescriptor jdbcTypeDescriptor) {
if ( jtdsDriver && TinyIntTypeDescriptor.INSTANCE == jdbcTypeDescriptor ) { if ( jtdsDriver && TinyIntTypeDescriptor.INSTANCE == jdbcTypeDescriptor ) {
return SmallIntTypeDescriptor.INSTANCE; return SmallIntTypeDescriptor.INSTANCE;
@ -174,6 +184,19 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
); );
typeContributions.contributeJdbcTypeDescriptor( ClobTypeDescriptor.CLOB_BINDING ); 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 @Override

View File

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

View File

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

View File

@ -31,7 +31,6 @@ import jakarta.persistence.LockModeType;
import jakarta.persistence.NoResultException; import jakarta.persistence.NoResultException;
import jakarta.persistence.Parameter; import jakarta.persistence.Parameter;
import jakarta.persistence.TemporalType; import jakarta.persistence.TemporalType;
import jakarta.persistence.TransactionRequiredException;
import org.hibernate.CacheMode; import org.hibernate.CacheMode;
import org.hibernate.FlushMode; import org.hibernate.FlushMode;
@ -46,7 +45,6 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.EntityManagerMessageLogger; import org.hibernate.internal.EntityManagerMessageLogger;
import org.hibernate.internal.HEMLogging; import org.hibernate.internal.HEMLogging;
import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.jpa.QueryHints; import org.hibernate.jpa.QueryHints;
import org.hibernate.jpa.internal.util.ConfigurationHelper; import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.hibernate.jpa.internal.util.FlushModeTypeHelper; import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
@ -415,8 +413,8 @@ public abstract class AbstractQuery<R> implements QueryImplementor<R> {
if ( getCacheMode() != null ) { if ( getCacheMode() != null ) {
putIfNotNull( hints, HINT_CACHE_MODE, getCacheMode() ); putIfNotNull( hints, HINT_CACHE_MODE, getCacheMode() );
putIfNotNull( hints, JAKARTA_SHARED_CACHE_RETRIEVE_MODE, CacheModeHelper.interpretCacheRetrieveMode( getCacheMode() ) ); putIfNotNull( hints, JAKARTA_SHARED_CACHE_RETRIEVE_MODE, getQueryOptions().getCacheRetrieveMode() );
putIfNotNull( hints, JAKARTA_SHARED_CACHE_STORE_MODE, CacheModeHelper.interpretCacheStoreMode( getCacheMode() ) ); putIfNotNull( hints, JAKARTA_SHARED_CACHE_STORE_MODE, getQueryOptions().getCacheStoreMode() );
putIfNotNull( hints, JPA_SHARED_CACHE_RETRIEVE_MODE, getQueryOptions().getCacheRetrieveMode() ); putIfNotNull( hints, JPA_SHARED_CACHE_RETRIEVE_MODE, getQueryOptions().getCacheRetrieveMode() );
putIfNotNull( hints, JPA_SHARED_CACHE_STORE_MODE, getQueryOptions().getCacheStoreMode() ); 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. * Sets the mapping model expressable for this parameter.
* *
* @param type The mapping model expressable * @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.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.EntityVersionMapping; import org.hibernate.metamodel.mapping.EntityVersionMapping;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.metamodel.mapping.JdbcMappingContainer;
import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.ModelPartContainer; import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.SqlExpressable;
import org.hibernate.metamodel.mapping.ValueMapping; import org.hibernate.metamodel.mapping.ValueMapping;
import org.hibernate.metamodel.mapping.internal.EmbeddedCollectionPart; import org.hibernate.metamodel.mapping.internal.EmbeddedCollectionPart;
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart; 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 QueryParameterImplementor<?> queryParameter = domainParameterXref.getQueryParameter( sqmParameter );
final QueryParameterBinding<?> binding = domainParameterBindings.getBinding( queryParameter ); final QueryParameterBinding<?> binding = domainParameterBindings.getBinding( queryParameter );
binding.setType( valueMapping ); if ( binding.setType( valueMapping ) ) {
replaceJdbcParametersType(
sqmParameter,
domainParameterXref.getSqmParameters( queryParameter ),
valueMapping
);
}
return new SqmParameterInterpretation( return new SqmParameterInterpretation(
sqmParameter, sqmParameter,
queryParameter, 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) { protected Expression consumeSqmParameter(SqmParameter sqmParameter) {
if ( sqmParameter.allowMultiValuedBinding() ) { if ( sqmParameter.allowMultiValuedBinding() ) {
final QueryParameterImplementor<?> domainParam = domainParameterXref.getQueryParameter( sqmParameter ); 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 QueryParameterImplementor<?> queryParameter = domainParameterXref.getQueryParameter( sqmParameter );
final QueryParameterBinding<?> binding = domainParameterBindings.getBinding( queryParameter ); final QueryParameterBinding<?> binding = domainParameterBindings.getBinding( queryParameter );
binding.setType( valueMapping ); if ( binding.setType( valueMapping ) ) {
replaceJdbcParametersType(
sqmParameter,
domainParameterXref.getSqmParameters( queryParameter ),
valueMapping
);
}
return new SqmParameterInterpretation( return new SqmParameterInterpretation(
sqmParameter, sqmParameter,
queryParameter, queryParameter,

View File

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

View File

@ -24,4 +24,13 @@ public class NullType extends JavaObjectType {
public NullType() { public NullType() {
super( ObjectNullResolvingJdbcTypeDescriptor.INSTANCE, JavaObjectTypeDescriptor.INSTANCE ); 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() "object", Object.class.getName()
); );
handle(
NullType.INSTANCE,
null,
basicTypeRegistry,
"null"
);
// todo (6.0) - ? how to handle DbTimestampType? // todo (6.0) - ? how to handle DbTimestampType?
// DbTimestampType was really just a variant of TimestampType with overridden // DbTimestampType was really just a variant of TimestampType with overridden
// version (opt lock) support // version (opt lock) support

View File

@ -12,6 +12,7 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Types; import java.sql.Types;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor; import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.WrapperOptions;
@ -56,6 +57,9 @@ public class FloatTypeDescriptor implements JdbcTypeDescriptor {
Integer length, Integer length,
Integer scale, Integer scale,
TypeConfiguration typeConfiguration) { 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 ); 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.Entity;
import jakarta.persistence.GeneratedValue; import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import javax.persistence.TypedQuery; import jakarta.persistence.TypedQuery;
import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.dialect.PostgreSQLDialect;

View File

@ -10,7 +10,7 @@ import jakarta.persistence.EntityManagerFactory;
import java.util.Arrays; import java.util.Arrays;
import org.hibernate.orm.test.jpa.TestingEntityManagerFactoryGenerator; 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.TestForIssue;
import org.hibernate.testing.orm.junit.BaseUnitTest; import org.hibernate.testing.orm.junit.BaseUnitTest;

View File

@ -10,7 +10,7 @@ import jakarta.persistence.EntityManagerFactory;
import java.util.Arrays; import java.util.Arrays;
import org.hibernate.cfg.AvailableSettings; 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.TestForIssue;
import org.hibernate.testing.orm.junit.BaseUnitTest; import org.hibernate.testing.orm.junit.BaseUnitTest;

View File

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

View File

@ -20,7 +20,7 @@ import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import org.hibernate.dialect.PostgreSQLDialect; 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.RequiresDialect;
import org.hibernate.testing.TestForIssue; import org.hibernate.testing.TestForIssue;