Improve SQL rendering performance by avoiding intermediate String objects

This commit is contained in:
Christian Beikov 2021-09-30 19:41:12 +02:00
parent 2cb1078fe3
commit c5baae7e11
47 changed files with 914 additions and 707 deletions

View File

@ -24,6 +24,7 @@ import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -335,17 +336,19 @@ public class CUBRIDDialect extends Dialect {
}
@Override
public String translateDatetimeFormat(String format) {
public void appendDatetimeFormat(SqlAppender appender, String format) {
//I do not know if CUBRID supports FM, but it
//seems that it does pad by default, so it needs it!
return OracleDialect.datetimeFormat( format, true, false )
appender.appendSql(
OracleDialect.datetimeFormat( format, true, false )
.replace("SSSSSS", "FF")
.replace("SSSSS", "FF")
.replace("SSSS", "FF")
.replace("SSS", "FF")
.replace("SS", "FF")
.replace("S", "FF")
.result();
.result()
);
}
@Override

View File

@ -31,6 +31,7 @@ import org.hibernate.query.spi.QueryEngine;
import org.hibernate.sql.JoinFragment;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -416,9 +417,9 @@ public class CacheDialect extends Dialect {
}
@Override
public String translateDatetimeFormat(String format) {
public void appendDatetimeFormat(SqlAppender appender, String format) {
//I don't think Cache needs FM
return OracleDialect.datetimeFormat( format, false, false ).result();
appender.appendSql( OracleDialect.datetimeFormat( format, false, false ).result() );
}
}

View File

@ -45,6 +45,7 @@ import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -68,7 +69,13 @@ import java.util.regex.Pattern;
import jakarta.persistence.TemporalType;
import static org.hibernate.type.descriptor.DateTimeUtils.formatAsTimestampWithMillis;
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_END;
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_DATE;
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_TIME;
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_TIMESTAMP;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis;
/**
* An SQL dialect for Firebird 2.0 and above.
@ -567,11 +574,14 @@ public class FirebirdDialect extends Dialect {
}
@Override
public String toBooleanValueString(boolean bool) {
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
//'boolean' type introduced in 3.0
return getVersion() < 300
? super.toBooleanValueString( bool )
: bool ? "true" : "false";
if ( getVersion() < 300 ) {
appender.appendSql( bool ? '1' : '0' );
}
else {
appender.appendSql( bool );
}
}
@Override
@ -704,23 +714,82 @@ public class FirebirdDialect extends Dialect {
}
}
@Override
protected String formatAsTimestamp(Date date, TimeZone jdbcTimeZone) {
return formatAsTimestampWithMillis( date, jdbcTimeZone );
public void appendDateTimeLiteral(
SqlAppender appender,
TemporalAccessor temporalAccessor,
TemporalType precision,
TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
appender.appendSql( JDBC_ESCAPE_START_DATE );
appendAsDate( appender, temporalAccessor );
appender.appendSql( JDBC_ESCAPE_END );
break;
case TIME:
appender.appendSql( JDBC_ESCAPE_START_TIME );
appendAsTime( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
appender.appendSql( JDBC_ESCAPE_END );
break;
case TIMESTAMP:
appender.appendSql( JDBC_ESCAPE_START_TIMESTAMP );
appendAsTimestampWithMillis( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
appender.appendSql( JDBC_ESCAPE_END );
break;
default:
throw new IllegalArgumentException();
}
}
public void appendDateTimeLiteral(SqlAppender appender, Date date, TemporalType precision, TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
appender.appendSql( JDBC_ESCAPE_START_DATE );
appendAsDate( appender, date );
appender.appendSql( JDBC_ESCAPE_END );
break;
case TIME:
appender.appendSql( JDBC_ESCAPE_START_TIME );
appendAsTime( appender, date );
appender.appendSql( JDBC_ESCAPE_END );
break;
case TIMESTAMP:
appender.appendSql( JDBC_ESCAPE_START_TIMESTAMP );
appendAsTimestampWithMillis( appender, date, jdbcTimeZone );
appender.appendSql( JDBC_ESCAPE_END );
break;
default:
throw new IllegalArgumentException();
}
}
public void appendDateTimeLiteral(
SqlAppender appender,
Calendar calendar,
TemporalType precision,
TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
appender.appendSql( JDBC_ESCAPE_START_DATE );
appendAsDate( appender, calendar );
appender.appendSql( JDBC_ESCAPE_END );
break;
case TIME:
appender.appendSql( JDBC_ESCAPE_START_TIME );
appendAsTime( appender, calendar );
appender.appendSql( JDBC_ESCAPE_END );
break;
case TIMESTAMP:
appender.appendSql( JDBC_ESCAPE_START_TIMESTAMP );
appendAsTimestampWithMillis( appender, calendar, jdbcTimeZone );
appender.appendSql( JDBC_ESCAPE_END );
break;
default:
throw new IllegalArgumentException();
}
}
@Override
protected String formatAsTimestamp(Calendar calendar, TimeZone jdbcTimeZone) {
return formatAsTimestampWithMillis( calendar, jdbcTimeZone );
}
@Override
protected String formatAsTimestamp(TemporalAccessor temporalAccessor, TimeZone jdbcTimeZone) {
return formatAsTimestampWithMillis( temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
}
@Override
public String translateDatetimeFormat(String format) {
public void appendDatetimeFormat(SqlAppender appender, String format) {
throw new NotYetImplementedFor6Exception( "format() function not supported on Firebird" );
}

View File

@ -45,6 +45,7 @@ import org.hibernate.query.sqm.sql.StandardSqmTranslatorFactory;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
@ -432,8 +433,8 @@ public class InformixDialect extends Dialect {
}
@Override
public String toBooleanValueString(boolean bool) {
return bool ? "'t'" : "'f'";
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
appender.appendSql( bool ? "'t'" : "'f'" );
}
@Override
@ -447,9 +448,9 @@ public class InformixDialect extends Dialect {
}
@Override
public String translateDatetimeFormat(String format) {
public void appendDatetimeFormat(SqlAppender appender, String format) {
//Informix' own variation of MySQL
return datetimeFormat( format ).result();
appender.appendSql( datetimeFormat( format ).result() );
}
public static Replacer datetimeFormat(String format) {

View File

@ -41,6 +41,7 @@ import org.hibernate.query.sqm.sql.StandardSqmTranslatorFactory;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
@ -197,10 +198,13 @@ public class IngresDialect extends Dialect {
}
@Override
public String toBooleanValueString(boolean bool) {
return getVersion() < 1000
? super.toBooleanValueString( bool )
: String.valueOf( bool );
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
if ( getVersion() < 1000 ) {
appender.appendSql( bool ? '1' : '0' );
}
else {
appender.appendSql( bool );
}
}
@ -496,8 +500,8 @@ public class IngresDialect extends Dialect {
}
@Override
public String translateDatetimeFormat(String format) {
return MySQLDialect.datetimeFormat( format ).result();
public void appendDatetimeFormat(SqlAppender appender, String format) {
appender.appendSql( MySQLDialect.datetimeFormat( format ).result() );
}
@Override

View File

@ -25,6 +25,7 @@ import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -271,7 +272,7 @@ public class MimerSQLDialect extends Dialect {
}
@Override
public String translateDatetimeFormat(String format) {
public void appendDatetimeFormat(SqlAppender appender, String format) {
throw new NotYetImplementedFor6Exception("format() function not supported on Mimer SQL");
}

View File

@ -26,6 +26,7 @@ import org.hibernate.sql.CaseFragment;
import org.hibernate.sql.DecodeCaseFragment;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -370,15 +371,17 @@ public class RDMSOS2200Dialect extends Dialect {
}
@Override
public String translateDatetimeFormat(String format) {
return OracleDialect.datetimeFormat( format, true, false ) //Does it really support FM?
public void appendDatetimeFormat(SqlAppender appender, String format) {
appender.appendSql(
OracleDialect.datetimeFormat( format, true, false ) //Does it really support FM?
.replace("SSSSSS", "MLS")
.replace("SSSSS", "MLS")
.replace("SSSS", "MLS")
.replace("SSS", "MLS")
.replace("SS", "MLS")
.replace("S", "MLS")
.result();
.result()
);
}
@Override

View File

@ -7,6 +7,11 @@
package org.hibernate.community.dialect;
import java.sql.Types;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import jakarta.persistence.TemporalType;
import org.hibernate.ScrollMode;
@ -39,6 +44,7 @@ import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolv
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -53,6 +59,9 @@ import static org.hibernate.query.TemporalUnit.EPOCH;
import static org.hibernate.query.TemporalUnit.MONTH;
import static org.hibernate.query.TemporalUnit.QUARTER;
import static org.hibernate.query.TemporalUnit.YEAR;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
/**
* An SQL dialect for SQLite.
@ -536,8 +545,8 @@ public class SQLiteDialect extends Dialect {
}
@Override
public String translateDatetimeFormat(String format) {
return datetimeFormat( format ).result();
public void appendDatetimeFormat(SqlAppender appender, String format) {
appender.appendSql( datetimeFormat( format ).result() );
}
public static Replacer datetimeFormat(String format) {
@ -600,18 +609,80 @@ public class SQLiteDialect extends Dialect {
}
@Override
protected String wrapDateLiteral(String date) {
return "date(" + date + ")";
public void appendDateTimeLiteral(
SqlAppender appender,
TemporalAccessor temporalAccessor,
TemporalType precision,
TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
appender.appendSql( "date(" );
appendAsDate( appender, temporalAccessor );
appender.appendSql( ')' );
break;
case TIME:
appender.appendSql( "time(" );
appendAsTime( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
appender.appendSql( ')' );
break;
case TIMESTAMP:
appender.appendSql( "datetime(" );
appendAsTimestampWithMicros( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
appender.appendSql( ')' );
break;
default:
throw new IllegalArgumentException();
}
}
@Override
protected String wrapTimeLiteral(String time) {
return "time(" + time + ")";
public void appendDateTimeLiteral(SqlAppender appender, Date date, TemporalType precision, TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
appender.appendSql( "date(" );
appendAsDate( appender, date );
appender.appendSql( ')' );
break;
case TIME:
appender.appendSql( "time(" );
appendAsTime( appender, date );
appender.appendSql( ')' );
break;
case TIMESTAMP:
appender.appendSql( "datetime(" );
appendAsTimestampWithMicros( appender, date, jdbcTimeZone );
appender.appendSql( ')' );
break;
default:
throw new IllegalArgumentException();
}
}
@Override
protected String wrapTimestampLiteral(String timestamp) {
return "datetime(" + timestamp + ")";
public void appendDateTimeLiteral(
SqlAppender appender,
Calendar calendar,
TemporalType precision,
TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
appender.appendSql( "date(" );
appendAsDate( appender, calendar );
appender.appendSql( ')' );
break;
case TIME:
appender.appendSql( "time(" );
appendAsTime( appender, calendar );
appender.appendSql( ')' );
break;
case TIMESTAMP:
appender.appendSql( "datetime(" );
appendAsTimestampWithMicros( appender, calendar, jdbcTimeZone );
appender.appendSql( ')' );
break;
default:
throw new IllegalArgumentException();
}
}
}

View File

@ -45,6 +45,7 @@ import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorHANADatabaseImpl;
@ -1551,10 +1552,13 @@ public abstract class AbstractHANADialect extends Dialect {
}
@Override
public String toBooleanValueString(boolean bool) {
return this.useLegacyBooleanType
? super.toBooleanValueString( bool )
: String.valueOf( bool );
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
if ( this.useLegacyBooleanType ) {
appender.appendSql( bool ? '1' : '0' );
}
else {
appender.appendSql( bool );
}
}
@Override
@ -1630,9 +1634,9 @@ public abstract class AbstractHANADialect extends Dialect {
}
@Override
public String translateDatetimeFormat(String format) {
public void appendDatetimeFormat(SqlAppender appender, String format) {
//I don't think HANA needs FM
return OracleDialect.datetimeFormat( format, false, false ).result();
appender.appendSql( OracleDialect.datetimeFormat( format, false, false ).result() );
}
@Override

View File

@ -25,7 +25,9 @@ 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.sql.ast.spi.SqlAppender;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
@ -326,7 +328,8 @@ public abstract class AbstractTransactSQLDialect extends Dialect {
}
@Override
public String formatBinaryLiteral(byte[] bytes) {
return "0x" + StandardBasicTypes.BINARY.toString( bytes );
public void appendBinaryLiteral(SqlAppender appender, byte[] bytes) {
appender.appendSql( "0x" );
PrimitiveByteArrayTypeDescriptor.INSTANCE.appendString( appender, bytes );
}
}

View File

@ -24,6 +24,7 @@ import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -32,15 +33,20 @@ import org.hibernate.type.StandardBasicTypes;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.TimeZone;
import jakarta.persistence.TemporalType;
import static org.hibernate.query.TemporalUnit.DAY;
import static org.hibernate.query.TemporalUnit.NATIVE;
import static org.hibernate.type.descriptor.DateTimeUtils.wrapAsAnsiDateLiteral;
import static org.hibernate.type.descriptor.DateTimeUtils.wrapAsAnsiTimeLiteral;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
/**
* A dialect for CockroachDB.
@ -135,8 +141,8 @@ public class CockroachDialect extends Dialect {
}
@Override
public String toBooleanValueString(boolean bool) {
return String.valueOf( bool );
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
appender.appendSql( bool );
}
@Override
@ -258,18 +264,80 @@ public class CockroachDialect extends Dialect {
}
@Override
protected String wrapDateLiteral(String date) {
return wrapAsAnsiDateLiteral(date);
public void appendDateTimeLiteral(
SqlAppender appender,
TemporalAccessor temporalAccessor,
TemporalType precision,
TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
appender.appendSql( "date '" );
appendAsDate( appender, temporalAccessor );
appender.appendSql( '\'' );
break;
case TIME:
appender.appendSql( "time '" );
appendAsTime( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
appender.appendSql( '\'' );
break;
case TIMESTAMP:
appender.appendSql( "timestamp with time zone '" );
appendAsTimestampWithMicros( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
appender.appendSql( '\'' );
break;
default:
throw new IllegalArgumentException();
}
}
@Override
protected String wrapTimeLiteral(String time) {
return wrapAsAnsiTimeLiteral(time);
public void appendDateTimeLiteral(SqlAppender appender, Date date, TemporalType precision, TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
appender.appendSql( "date '" );
appendAsDate( appender, date );
appender.appendSql( '\'' );
break;
case TIME:
appender.appendSql( "time '" );
appendAsTime( appender, date );
appender.appendSql( '\'' );
break;
case TIMESTAMP:
appender.appendSql( "timestamp with time zone '" );
appendAsTimestampWithMicros( appender,date, jdbcTimeZone );
appender.appendSql( '\'' );
break;
default:
throw new IllegalArgumentException();
}
}
@Override
protected String wrapTimestampLiteral(String timestamp) {
return "timestamp with time zone '" + timestamp + "'";
public void appendDateTimeLiteral(
SqlAppender appender,
Calendar calendar,
TemporalType precision,
TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
appender.appendSql( "date '" );
appendAsDate( appender, calendar );
appender.appendSql( '\'' );
break;
case TIME:
appender.appendSql( "time '" );
appendAsTime( appender, calendar );
appender.appendSql( '\'' );
break;
case TIMESTAMP:
appender.appendSql( "timestamp with time zone '" );
appendAsTimestampWithMicros( appender, calendar, jdbcTimeZone );
appender.appendSql( '\'' );
break;
default:
throw new IllegalArgumentException();
}
}
/**
@ -363,8 +431,8 @@ public class CockroachDialect extends Dialect {
}
@Override
public String translateDatetimeFormat(String format) {
return SpannerDialect.datetimeFormat( format ).result();
public void appendDatetimeFormat(SqlAppender appender, String format) {
appender.appendSql( SpannerDialect.datetimeFormat( format ).result() );
}
@Override

View File

@ -36,6 +36,7 @@ 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.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -44,6 +45,7 @@ import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNo
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.*;
import java.sql.CallableStatement;
@ -593,8 +595,10 @@ public class DB2Dialect extends Dialect {
}
@Override
public String formatBinaryLiteral(byte[] bytes) {
return "BX'" + StandardBasicTypes.BINARY.toString( bytes ) + "'";
public void appendBinaryLiteral(SqlAppender appender, byte[] bytes) {
appender.appendSql( "BX'" );
PrimitiveByteArrayTypeDescriptor.INSTANCE.appendString( appender, bytes );
appender.appendSql( '\'' );
}
@Override
@ -735,9 +739,9 @@ public class DB2Dialect extends Dialect {
}
@Override
public String translateDatetimeFormat(String format) {
public void appendDatetimeFormat(SqlAppender appender, String format) {
//DB2 does not need nor support FM
return OracleDialect.datetimeFormat( format, false, false ).result();
appender.appendSql( OracleDialect.datetimeFormat( format, false, false ).result() );
}
@Override
@ -752,12 +756,12 @@ public class DB2Dialect extends Dialect {
}
@Override
public String toBooleanValueString(boolean bool) {
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
if ( getVersion() < 1100 ) {
return bool ? "1" : "0";
appender.appendSql( bool ? '1' : '0' );
}
else {
return bool ? "true" : "false";
appender.appendSql( bool );
}
}

View File

@ -257,7 +257,7 @@ public class DB2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAst
}
else if ( expression instanceof Summarization ) {
Summarization summarization = (Summarization) expression;
appendSql( summarization.getKind().name().toLowerCase() );
appendSql( summarization.getKind().sqlText() );
appendSql( OPEN_PARENTHESIS );
renderCommaSeparated( summarization.getGroupings() );
appendSql( CLOSE_PARENTHESIS );

View File

@ -48,6 +48,7 @@ import org.hibernate.sql.DerbyCaseFragment;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -355,10 +356,13 @@ public class DerbyDialect extends Dialect {
}
@Override
public String toBooleanValueString(boolean bool) {
return getVersion() < 1070
? super.toBooleanValueString( bool )
: String.valueOf( bool );
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
if ( getVersion() < 1070 ) {
appender.appendSql( bool ? '1' : '0' );
}
else {
appender.appendSql( bool );
}
}
@Override
@ -608,7 +612,7 @@ public class DerbyDialect extends Dialect {
}
@Override
public String translateDatetimeFormat(String format) {
public void appendDatetimeFormat(SqlAppender appender, String format) {
throw new NotYetImplementedFor6Exception("format() function not supported on Derby");
}

View File

@ -191,7 +191,7 @@ public class DerbySqlAstTranslator<T extends JdbcOperation> extends AbstractSqlA
}
else if ( expression instanceof Summarization ) {
Summarization summarization = (Summarization) expression;
appendSql( summarization.getKind().name().toLowerCase() );
appendSql( summarization.getKind().sqlText() );
appendSql( OPEN_PARENTHESIS );
renderCommaSeparated( summarization.getGroupings() );
appendSql( CLOSE_PARENTHESIS );

View File

@ -73,6 +73,7 @@ import org.hibernate.sql.*;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
@ -82,6 +83,7 @@ import org.hibernate.tool.schema.spi.Exporter;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ClobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.LongNVarcharTypeDescriptor;
@ -97,7 +99,6 @@ import java.sql.*;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.hibernate.type.descriptor.DateTimeUtils.*;
@ -137,16 +138,10 @@ public abstract class Dialect implements ConversionContext {
* Characters used as closing for quoting SQL identifiers
*/
public static final String CLOSED_QUOTE = "`\"]";
private static final Pattern SINGLE_QUOTE_PATTERN = Pattern.compile(
"'",
Pattern.LITERAL
);
private static final Pattern ESCAPE_CLOSING_COMMENT_PATTERN = Pattern.compile( "\\*/" );
private static final Pattern ESCAPE_OPENING_COMMENT_PATTERN = Pattern.compile( "/\\*" );
public static final String TWO_SINGLE_QUOTES_REPLACEMENT = Matcher.quoteReplacement( "''" );
private final TypeNames typeNames = new TypeNames();
private final TypeNames hibernateTypeNames = new TypeNames();
@ -2399,7 +2394,13 @@ public abstract class Dialect implements ConversionContext {
* @return The appropriate SQL literal.
*/
public String toBooleanValueString(boolean bool) {
return bool ? "1" : "0";
final StringBuilder sb = new StringBuilder();
appendBooleanValueString( sb::append, bool );
return sb.toString();
}
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
appender.appendSql( bool ? '1' : '0' );
}
@ -3736,7 +3737,21 @@ public abstract class Dialect implements ConversionContext {
* @return escaped String
*/
public String inlineLiteral(String literal) {
return String.format( "\'%s\'", escapeLiteral( literal ) );
final StringBuilder sb = new StringBuilder( literal.length() + 2 );
appendLiteral( sb::append, literal );
return sb.toString();
}
public void appendLiteral(SqlAppender appender, String literal) {
appender.appendSql( '\'' );
for ( int i = 0; i < literal.length(); i++ ) {
final char c = literal.charAt( i );
if ( c == '\'' ) {
appender.appendSql( '\'' );
}
appender.appendSql( c );
}
appender.appendSql( '\'' );
}
/**
@ -3751,15 +3766,6 @@ public abstract class Dialect implements ConversionContext {
return true;
}
/**
* Escape String literal.
*
* @return escaped String
*/
protected String escapeLiteral(String literal) {
return SINGLE_QUOTE_PATTERN.matcher( literal ).replaceAll( TWO_SINGLE_QUOTES_REPLACEMENT );
}
/**
* Modify the SQL, adding hints or comments, if necessary
*/
@ -3943,8 +3949,10 @@ public abstract class Dialect implements ConversionContext {
return true;
}
public String formatBinaryLiteral(byte[] bytes) {
return "X'" + StandardBasicTypes.BINARY.toString( bytes ) + "'";
public void appendBinaryLiteral(SqlAppender appender, byte[] bytes) {
appender.appendSql( "X'" );
PrimitiveByteArrayTypeDescriptor.INSTANCE.appendString( appender, bytes );
appender.appendSql( '\'' );
}
public RowLockStrategy getLockRowIdentifier(LockMode lockMode) {
@ -4109,11 +4117,11 @@ public abstract class Dialect implements ConversionContext {
* @return a pattern accepted by the function that
* formats dates and times in this dialect
*/
public String translateDatetimeFormat(String format) {
public void appendDatetimeFormat(SqlAppender appender, String format) {
//most databases support a datetime format
//copied from Oracle's to_char() function,
//with some minor variation
return OracleDialect.datetimeFormat( format, true, false ).result();
appender.appendSql( OracleDialect.datetimeFormat( format, true, false ).result() );
}
/**
@ -4196,72 +4204,80 @@ public abstract class Dialect implements ConversionContext {
}
}
protected String wrapTimestampLiteral(String timestamp) {
return wrapAsJdbcTimestampLiteral( timestamp );
}
protected String wrapDateLiteral(String date) {
return wrapAsJdbcDateLiteral( date );
}
protected String wrapTimeLiteral(String time) {
return wrapAsJdbcTimeLiteral( time );
}
public String formatDateTimeLiteral(
public void appendDateTimeLiteral(
SqlAppender appender,
TemporalAccessor temporalAccessor,
TemporalType precision,
TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
return wrapDateLiteral( formatAsDate( temporalAccessor ) );
appender.appendSql( JDBC_ESCAPE_START_DATE );
appendAsDate( appender, temporalAccessor );
appender.appendSql( JDBC_ESCAPE_END );
break;
case TIME:
return wrapTimeLiteral( formatAsTime( temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone ) );
appender.appendSql( JDBC_ESCAPE_START_TIME );
appendAsTime( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
appender.appendSql( JDBC_ESCAPE_END );
break;
case TIMESTAMP:
return wrapTimestampLiteral( formatAsTimestamp( temporalAccessor, jdbcTimeZone ) );
appender.appendSql( JDBC_ESCAPE_START_TIMESTAMP );
appendAsTimestampWithMicros( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
appender.appendSql( JDBC_ESCAPE_END );
break;
default:
throw new IllegalArgumentException();
}
}
protected String formatAsTimestamp(TemporalAccessor temporalAccessor, TimeZone jdbcTimeZone) {
return formatAsTimestampWithMicros( temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
}
public String formatDateTimeLiteral(Date date, TemporalType precision, TimeZone jdbcTimeZone) {
public void appendDateTimeLiteral(SqlAppender appender, Date date, TemporalType precision, TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
return wrapDateLiteral( formatAsDate( date ) );
appender.appendSql( JDBC_ESCAPE_START_DATE );
appendAsDate( appender, date );
appender.appendSql( JDBC_ESCAPE_END );
break;
case TIME:
return wrapTimeLiteral( formatAsTime( date ) );
appender.appendSql( JDBC_ESCAPE_START_TIME );
appendAsTime( appender, date );
appender.appendSql( JDBC_ESCAPE_END );
break;
case TIMESTAMP:
return wrapTimestampLiteral( formatAsTimestamp( date, jdbcTimeZone) );
appender.appendSql( JDBC_ESCAPE_START_TIMESTAMP );
appendAsTimestampWithMicros( appender, date, jdbcTimeZone );
appender.appendSql( JDBC_ESCAPE_END );
break;
default:
throw new IllegalArgumentException();
}
}
protected String formatAsTimestamp(Date date, TimeZone jdbcTimeZone) {
return formatAsTimestampWithMicros( date, jdbcTimeZone );
}
public String formatDateTimeLiteral(Calendar calendar, TemporalType precision, TimeZone jdbcTimeZone) {
public void appendDateTimeLiteral(
SqlAppender appender,
Calendar calendar,
TemporalType precision,
TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
return wrapDateLiteral( formatAsDate( calendar ) );
appender.appendSql( JDBC_ESCAPE_START_DATE );
appendAsDate( appender, calendar );
appender.appendSql( JDBC_ESCAPE_END );
break;
case TIME:
return wrapTimeLiteral( formatAsTime( calendar ) );
appender.appendSql( JDBC_ESCAPE_START_TIME );
appendAsTime( appender, calendar );
appender.appendSql( JDBC_ESCAPE_END );
break;
case TIMESTAMP:
return wrapTimestampLiteral( formatAsTimestamp( calendar, jdbcTimeZone ) );
appender.appendSql( JDBC_ESCAPE_START_TIMESTAMP );
appendAsTimestampWithMicros( appender, calendar, jdbcTimeZone );
appender.appendSql( JDBC_ESCAPE_END );
break;
default:
throw new IllegalArgumentException();
}
}
protected String formatAsTimestamp(Calendar calendar, TimeZone jdbcTimeZone) {
return formatAsTimestampWithMicros( calendar, jdbcTimeZone );
}
/**
* Whether the Dialect supports timezone offset in temporal literals.
*/

View File

@ -44,6 +44,7 @@ import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -269,8 +270,8 @@ public class H2Dialect extends Dialect {
}
@Override
public String toBooleanValueString(boolean bool) {
return String.valueOf( bool );
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
appender.appendSql( bool );
}
@Override
@ -462,17 +463,21 @@ public class H2Dialect extends Dialect {
}
@Override
public String translateDatetimeFormat(String format) {
public void appendDatetimeFormat(SqlAppender appender, String format) {
if ( version == 104200 ) {
// See https://github.com/h2database/h2database/issues/2518
return OracleDialect.datetimeFormat( format, true, true ).result();
appender.appendSql( OracleDialect.datetimeFormat( format, true, true ).result() );
}
return new Replacer( format, "'", "''" )
else {
appender.appendSql(
new Replacer( format, "'", "''" )
.replace("e", "u")
.replace( "xxx", "XXX" )
.replace( "xx", "XX" )
.replace( "x", "X" )
.result();
.result()
);
}
}
public String translateExtractField(TemporalUnit unit) {

View File

@ -56,6 +56,7 @@ import org.hibernate.query.sqm.mutation.internal.idtable.TempIdTableExporter;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -646,8 +647,8 @@ public class HSQLDialect extends Dialect {
}
@Override
public String toBooleanValueString(boolean bool) {
return String.valueOf( bool );
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
appender.appendSql( bool );
}
@Override
@ -698,8 +699,9 @@ public class HSQLDialect extends Dialect {
}
@Override
public String translateDatetimeFormat(String format) {
return OracleDialect.datetimeFormat( format, false, false )
public void appendDatetimeFormat(SqlAppender appender, String format) {
appender.appendSql(
OracleDialect.datetimeFormat( format, false, false )
// HSQL is case sensitive i.e. requires MONTH and DAY instead of Month and Day
.replace("MMMM", "MONTH")
.replace("EEEE", "DAY")
@ -709,7 +711,8 @@ public class HSQLDialect extends Dialect {
.replace("SSS", "FF")
.replace("SS", "FF")
.replace("S", "FF")
.result();
.result()
);
}
@Override

View File

@ -102,7 +102,7 @@ public class MariaDBSqlAstTranslator<T extends JdbcOperation> extends AbstractSq
Summarization summarization = (Summarization) expression;
renderCommaSeparated( summarization.getGroupings() );
appendSql( " with " );
appendSql( summarization.getKind().name().toLowerCase() );
appendSql( summarization.getKind().sqlText() );
}
else {
expression.accept( this );

View File

@ -51,6 +51,7 @@ 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.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -940,13 +941,26 @@ public class MySQLDialect extends Dialect {
}
@Override
protected String escapeLiteral(String literal) {
return super.escapeLiteral( literal ).replace("\\", "\\\\");
public void appendLiteral(SqlAppender appender, String literal) {
appender.appendSql( '\'' );
for ( int i = 0; i < literal.length(); i++ ) {
final char c = literal.charAt( i );
switch ( c ) {
case '\'':
appender.appendSql( '\'' );
break;
case '\\':
appender.appendSql( '\\' );
break;
}
appender.appendSql( c );
}
appender.appendSql( '\'' );
}
@Override
public String translateDatetimeFormat(String format) {
return datetimeFormat( format ).result();
public void appendDatetimeFormat(SqlAppender appender, String format) {
appender.appendSql( datetimeFormat( format ).result() );
}
public static Replacer datetimeFormat(String format) {

View File

@ -103,7 +103,7 @@ public class MySQLSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlA
Summarization summarization = (Summarization) expression;
renderCommaSeparated( summarization.getGroupings() );
appendSql( " with " );
appendSql( summarization.getKind().name().toLowerCase() );
appendSql( summarization.getKind().sqlText() );
}
else {
expression.accept( this );

View File

@ -51,6 +51,7 @@ import org.hibernate.sql.*;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -59,6 +60,7 @@ 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.java.PrimitiveByteArrayTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.BlobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.NullJdbcTypeDescriptor;
@ -1185,10 +1187,10 @@ public class OracleDialect extends Dialect {
}
@Override
public String translateDatetimeFormat(String format) {
public void appendDatetimeFormat(SqlAppender appender, String format) {
// Unlike other databases, Oracle requires an explicit reset for the fm modifier,
// otherwise all following pattern variables trim zeros
return datetimeFormat( format, true, true ).result();
appender.appendSql( datetimeFormat( format, true, true ).result() );
}
public static Replacer datetimeFormat(String format, boolean useFm, boolean resetFm) {
@ -1277,8 +1279,10 @@ public class OracleDialect extends Dialect {
}
@Override
public String formatBinaryLiteral(byte[] bytes) {
return "hextoraw('" + StandardBasicTypes.BINARY.toString( bytes ) + "')";
public void appendBinaryLiteral(SqlAppender appender, byte[] bytes) {
appender.appendSql( "hextoraw('" );
PrimitiveByteArrayTypeDescriptor.INSTANCE.appendString( appender, bytes );
appender.appendSql( "')" );
}
@Override

View File

@ -318,7 +318,7 @@ public class OracleSqlAstTranslator<T extends JdbcOperation> extends AbstractSql
}
else if ( expression instanceof Summarization ) {
Summarization summarization = (Summarization) expression;
appendSql( summarization.getKind().name().toLowerCase() );
appendSql( summarization.getKind().sqlText() );
appendSql( OPEN_PARENTHESIS );
renderCommaSeparated( summarization.getGroupings() );
appendSql( CLOSE_PARENTHESIS );

View File

@ -11,9 +11,14 @@ import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import jakarta.persistence.TemporalType;
import org.hibernate.LockMode;
@ -54,12 +59,14 @@ 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.SqlAppender;
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.java.PrimitiveByteArrayTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.BlobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ClobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
@ -67,8 +74,9 @@ import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcTypeDescript
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
import static org.hibernate.query.TemporalUnit.*;
import static org.hibernate.type.descriptor.DateTimeUtils.wrapAsAnsiDateLiteral;
import static org.hibernate.type.descriptor.DateTimeUtils.wrapAsAnsiTimeLiteral;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
/**
* An SQL dialect for Postgres 8 and above.
@ -544,8 +552,8 @@ public class PostgreSQLDialect extends Dialect {
}
@Override
public String toBooleanValueString(boolean bool) {
return String.valueOf( bool );
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
appender.appendSql( bool );
}
@Override
@ -714,8 +722,8 @@ public class PostgreSQLDialect extends Dialect {
}
@Override
public String translateDatetimeFormat(String format) {
return datetimeFormat( format ).result();
public void appendDatetimeFormat(SqlAppender appender, String format) {
appender.appendSql( datetimeFormat( format ).result() );
}
public Replacer datetimeFormat(String format) {
@ -750,23 +758,87 @@ public class PostgreSQLDialect extends Dialect {
}
@Override
public String formatBinaryLiteral(byte[] bytes) {
return "bytea '\\x" + StandardBasicTypes.BINARY.toString( bytes ) + "'";
public void appendBinaryLiteral(SqlAppender appender, byte[] bytes) {
appender.appendSql( "bytea '\\x" );
PrimitiveByteArrayTypeDescriptor.INSTANCE.appendString( appender, bytes );
appender.appendSql( '\'' );
}
@Override
protected String wrapDateLiteral(String date) {
return wrapAsAnsiDateLiteral(date);
public void appendDateTimeLiteral(
SqlAppender appender,
TemporalAccessor temporalAccessor,
TemporalType precision,
TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
appender.appendSql( "date '" );
appendAsDate( appender, temporalAccessor );
appender.appendSql( '\'' );
break;
case TIME:
appender.appendSql( "time '" );
appendAsTime( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
appender.appendSql( '\'' );
break;
case TIMESTAMP:
appender.appendSql( "timestamp with time zone '" );
appendAsTimestampWithMicros( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
appender.appendSql( '\'' );
break;
default:
throw new IllegalArgumentException();
}
}
@Override
protected String wrapTimeLiteral(String time) {
return wrapAsAnsiTimeLiteral(time);
public void appendDateTimeLiteral(SqlAppender appender, Date date, TemporalType precision, TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
appender.appendSql( "date '" );
appendAsDate( appender, date );
appender.appendSql( '\'' );
break;
case TIME:
appender.appendSql( "time '" );
appendAsTime( appender, date );
appender.appendSql( '\'' );
break;
case TIMESTAMP:
appender.appendSql( "timestamp with time zone '" );
appendAsTimestampWithMicros( appender, date, jdbcTimeZone );
appender.appendSql( '\'' );
break;
default:
throw new IllegalArgumentException();
}
}
@Override
protected String wrapTimestampLiteral(String timestamp) {
return "timestamp with time zone '" + timestamp + "'";
public void appendDateTimeLiteral(
SqlAppender appender,
Calendar calendar,
TemporalType precision,
TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
appender.appendSql( "date '" );
appendAsDate( appender, calendar );
appender.appendSql( '\'' );
break;
case TIME:
appender.appendSql( "time '" );
appendAsTime( appender, calendar );
appender.appendSql( '\'' );
break;
case TIMESTAMP:
appender.appendSql( "timestamp with time zone '" );
appendAsTimestampWithMicros( appender, calendar, jdbcTimeZone );
appender.appendSql( '\'' );
break;
default:
throw new IllegalArgumentException();
}
}
private String withTimeout(String lockString, int timeout) {

View File

@ -129,7 +129,7 @@ public class PostgreSQLSqlAstTranslator<T extends JdbcOperation> extends Abstrac
else if ( expression instanceof Summarization ) {
Summarization summarization = (Summarization) expression;
if ( getDialect().getVersion() >= 950 ) {
appendSql( summarization.getKind().name().toLowerCase() );
appendSql( summarization.getKind().sqlText() );
appendSql( OPEN_PARENTHESIS );
renderCommaSeparated( summarization.getGroupings() );
appendSql( CLOSE_PARENTHESIS );

View File

@ -39,24 +39,33 @@ import org.hibernate.query.spi.QueryEngine;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.internal.StandardSequenceExporter;
import org.hibernate.tool.schema.spi.Exporter;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.SmallIntTypeDescriptor;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.regex.Pattern;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import jakarta.persistence.TemporalType;
import static java.util.regex.Pattern.compile;
import static org.hibernate.query.TemporalUnit.NANOSECOND;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
/**
* A dialect for Microsoft SQL Server 2000 and above
@ -674,8 +683,8 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
}
@Override
public String translateDatetimeFormat(String format) {
return datetimeFormat(format).result();
public void appendDatetimeFormat(SqlAppender appender, String format) {
appender.appendSql( datetimeFormat(format).result() );
}
public static Replacer datetimeFormat(String format) {
@ -717,31 +726,96 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
.replace("x", "zz");
}
private static final Pattern OFFSET_PATTERN = compile(".*[-+]\\d{2}(:\\d{2})?$");
@Override
public String formatBinaryLiteral(byte[] bytes) {
return "0x" + StandardBasicTypes.BINARY.toString( bytes );
public void appendBinaryLiteral(SqlAppender appender, byte[] bytes) {
appender.appendSql( "0x" );
PrimitiveByteArrayTypeDescriptor.INSTANCE.appendString( appender, bytes );
}
@Override
protected String wrapTimestampLiteral(String timestamp) {
//needed because the {ts ... } JDBC escape chokes on microseconds
return OFFSET_PATTERN.matcher( timestamp ).matches()
? "cast('" + timestamp + "' as datetimeoffset)"
: "cast('" + timestamp + "' as datetime2)";
}
@Override
protected String wrapTimeLiteral(String time) {
public void appendDateTimeLiteral(
SqlAppender appender,
TemporalAccessor temporalAccessor,
TemporalType precision,
TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
appender.appendSql( "cast('" );
appendAsDate( appender, temporalAccessor );
appender.appendSql( "' as date)" );
break;
case TIME:
//needed because the {t ... } JDBC is just buggy
return "cast('" + time + "' as time)";
appender.appendSql( "cast('" );
appendAsTime( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
appender.appendSql( "' as time)" );
break;
case TIMESTAMP:
appender.appendSql( "cast('" );
appendAsTimestampWithMicros( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
//needed because the {ts ... } JDBC escape chokes on microseconds
if ( supportsTemporalLiteralOffset() && temporalAccessor.isSupported( ChronoField.OFFSET_SECONDS ) ) {
appender.appendSql( "' as datetimeoffset)" );
}
else {
appender.appendSql( "' as datetime2)" );
}
break;
default:
throw new IllegalArgumentException();
}
}
@Override
protected String wrapDateLiteral(String date) {
//possibly not needed
return "cast('" + date + "' as date)";
public void appendDateTimeLiteral(SqlAppender appender, Date date, TemporalType precision, TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
appender.appendSql( "cast('" );
appendAsDate( appender, date );
appender.appendSql( "' as date)" );
break;
case TIME:
//needed because the {t ... } JDBC is just buggy
appender.appendSql( "cast('" );
appendAsTime( appender, date );
appender.appendSql( "' as time)" );
break;
case TIMESTAMP:
appender.appendSql( "cast('" );
appendAsTimestampWithMicros( appender, date, jdbcTimeZone );
appender.appendSql( "' as datetimeoffset)" );
break;
default:
throw new IllegalArgumentException();
}
}
@Override
public void appendDateTimeLiteral(
SqlAppender appender,
Calendar calendar,
TemporalType precision,
TimeZone jdbcTimeZone) {
switch ( precision ) {
case DATE:
appender.appendSql( "cast('" );
appendAsDate( appender, calendar );
appender.appendSql( "' as date)" );
break;
case TIME:
//needed because the {t ... } JDBC is just buggy
appender.appendSql( "cast('" );
appendAsTime( appender, calendar );
appender.appendSql( "' as time)" );
break;
case TIMESTAMP:
appender.appendSql( "cast('" );
appendAsTimestampWithMicros( appender, calendar, jdbcTimeZone );
appender.appendSql( "' as datetime2)" );
break;
default:
throw new IllegalArgumentException();
}
}
@Override

View File

@ -52,12 +52,12 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
int searchIndex = 0;
int unionIndex;
while ( ( unionIndex = tableExpression.indexOf( UNION_ALL, searchIndex ) ) != -1 ) {
appendSql( tableExpression.substring( searchIndex, unionIndex ) );
append( tableExpression, searchIndex, unionIndex );
renderLockHint( lockMode );
appendSql( UNION_ALL );
searchIndex = unionIndex + UNION_ALL.length();
}
appendSql( tableExpression.substring( searchIndex, tableExpression.length() - 2 ) );
append( tableExpression, searchIndex, tableExpression.length() - 2 );
renderLockHint( lockMode );
appendSql( " )" );
@ -82,24 +82,43 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
private void renderLockHint(LockMode lockMode) {
if ( getDialect().getVersion() >= 9 ) {
final int effectiveLockTimeout = getEffectiveLockTimeout( lockMode );
final String writeLockStr = effectiveLockTimeout == LockOptions.SKIP_LOCKED ? "updlock" : "updlock,holdlock";
final String readLockStr = effectiveLockTimeout == LockOptions.SKIP_LOCKED ? "updlock" : "holdlock";
final String noWaitStr = effectiveLockTimeout == LockOptions.NO_WAIT ? ",nowait" : "";
final String skipLockStr = effectiveLockTimeout == LockOptions.SKIP_LOCKED ? ",readpast" : "";
switch ( lockMode ) {
//noinspection deprecation
case UPGRADE:
case PESSIMISTIC_WRITE:
case WRITE:
appendSql( " with (" + writeLockStr + ",rowlock" + noWaitStr + skipLockStr + ")" );
switch ( effectiveLockTimeout ) {
case LockOptions.SKIP_LOCKED:
appendSql( " with (updlock,rowlock,readpast)" );
break;
case LockOptions.NO_WAIT:
appendSql( " with (updlock,holdlock,rowlock,nowait)" );
break;
default:
appendSql( " with (updlock,holdlock,rowlock)" );
break;
}
break;
case PESSIMISTIC_READ:
appendSql( " with (" + readLockStr + ",rowlock" + noWaitStr + skipLockStr + ")" );
switch ( effectiveLockTimeout ) {
case LockOptions.SKIP_LOCKED:
appendSql( " with (updlock,rowlock,readpast)" );
break;
case LockOptions.NO_WAIT:
appendSql( " with (holdlock,rowlock,nowait)");
break;
default:
appendSql( " with (holdlock,rowlock)");
break;
}
break;
case UPGRADE_SKIPLOCKED:
appendSql( " with (updlock,rowlock,readpast" + noWaitStr + ")" );
if ( effectiveLockTimeout == LockOptions.NO_WAIT ) {
appendSql( " with (updlock,rowlock,readpast,nowait)" );
}
else {
appendSql( " with (updlock,rowlock,readpast)" );
}
break;
case UPGRADE_NOWAIT:
appendSql( " with (updlock,holdlock,rowlock,nowait)" );
@ -322,7 +341,7 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
Summarization summarization = (Summarization) expression;
renderCommaSeparated( summarization.getGroupings() );
appendSql( " with " );
appendSql( summarization.getKind().name().toLowerCase() );
appendSql( summarization.getKind().sqlText() );
}
else {
expression.accept( this );

View File

@ -34,6 +34,7 @@ import org.hibernate.query.TemporalUnit;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -416,8 +417,8 @@ public class SpannerDialect extends Dialect {
}
@Override
public String toBooleanValueString(boolean bool) {
return String.valueOf( bool );
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
appender.appendSql( bool );
}
@Override
@ -489,8 +490,8 @@ public class SpannerDialect extends Dialect {
}
@Override
public String translateDatetimeFormat(String format) {
return datetimeFormat( format ).result();
public void appendDatetimeFormat(SqlAppender appender, String format) {
appender.appendSql( datetimeFormat( format ).result() );
}
public static Replacer datetimeFormat(String format) {

View File

@ -32,6 +32,7 @@ import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
@ -317,7 +318,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
}
@Override
public String translateDatetimeFormat(String format) {
public void appendDatetimeFormat(SqlAppender appender, String format) {
throw new NotYetImplementedFor6Exception( "format() function not supported on Sybase");
}

View File

@ -105,7 +105,7 @@ public class CountFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
sqlAppender.appendSql( concatOperator );
sqlAppender.appendSql( "''" );
sqlAppender.appendSql( ",'\\0'),''),'\\0" );
sqlAppender.appendSql( Integer.toString( argumentNumber ) );
sqlAppender.appendSql( argumentNumber );
sqlAppender.appendSql( "')" );
sqlAppender.appendSql( concatOperator );
sqlAppender.appendSql( "'\\0'" );
@ -117,7 +117,7 @@ public class CountFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
sqlAppender.appendSql( concatOperator );
sqlAppender.appendSql( "''" );
sqlAppender.appendSql( ",'\\0'),''),'\\0" );
sqlAppender.appendSql( Integer.toString( argumentNumber ) );
sqlAppender.appendSql( argumentNumber );
sqlAppender.appendSql( "')" );
if ( caseWrapper ) {
sqlAppender.appendSql( " else null end" );

View File

@ -38,7 +38,7 @@ public class CurrentFunction
SqlAppender sqlAppender,
List<SqlAstNode> arguments,
SqlAstTranslator<?> walker) {
sqlAppender.appendSql(sql);
sqlAppender.appendSql( sql );
}
@Override

View File

@ -58,7 +58,7 @@ public class SQLServerFormatEmulation extends AbstractSqmSelfRenderingFunctionDe
datetime.accept( walker );
}
sqlAppender.appendSql(",'");
sqlAppender.appendSql( dialect.translateDatetimeFormat( format.getFormat() ) );
dialect.appendDatetimeFormat( sqlAppender, format.getFormat() );
sqlAppender.appendSql("')");
}

View File

@ -16,7 +16,6 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
@ -362,6 +361,34 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
sqlBuffer.append( fragment );
}
@Override
public void appendSql(int value) {
sqlBuffer.append( value );
}
@Override
public void appendSql(boolean value) {
sqlBuffer.append( value );
}
@Override
public Appendable append(CharSequence csq) {
sqlBuffer.append( csq );
return this;
}
@Override
public Appendable append(CharSequence csq, int start, int end) {
sqlBuffer.append( csq, start, end );
return this;
}
@Override
public Appendable append(char c) {
sqlBuffer.append( c );
return this;
}
protected JdbcServices getJdbcServices() {
return getSessionFactory().getJdbcServices();
}
@ -964,7 +991,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
}
else {
forUpdate.merge( getLockOptions() );
forUpdate.applyAliases( dialect.getWriteRowLockStrategy(), querySpec );
forUpdate.applyAliases( getDialect().getWriteRowLockStrategy(), querySpec );
if ( LockMode.READ.lessThan( forUpdate.getLockMode() ) ) {
final LockStrategy lockStrategy = determineLockingStrategy(
querySpec,
@ -994,7 +1021,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
else if ( lockOptions.getLockMode() != LockMode.NONE ) {
final ForUpdateClause forUpdateClause = new ForUpdateClause();
forUpdateClause.merge( getLockOptions() );
forUpdateClause.applyAliases( dialect.getWriteRowLockStrategy(), querySpec );
forUpdateClause.applyAliases( getDialect().getWriteRowLockStrategy(), querySpec );
if ( LockMode.READ.lessThan( forUpdateClause.getLockMode() ) ) {
final LockStrategy lockStrategy = determineLockingStrategy(
querySpec,
@ -1021,7 +1048,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
}
else if ( forUpdate != null ) {
forUpdate.merge( getLockOptions() );
forUpdate.applyAliases( dialect.getWriteRowLockStrategy(), querySpec );
forUpdate.applyAliases( getDialect().getWriteRowLockStrategy(), querySpec );
if ( LockMode.READ.lessThan( forUpdate.getLockMode() ) ) {
final LockStrategy lockStrategy = determineLockingStrategy( querySpec, forUpdate, null );
switch ( lockStrategy ) {
@ -1095,7 +1122,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
default:
if ( getDialect().supportsWait() ) {
appendSql( " wait " );
appendSql( Integer.toString( Math.round( timeoutMillis / 1e3f ) ) );
appendSql( Math.round( timeoutMillis / 1e3f ) );
}
break;
}
@ -1484,7 +1511,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
visitSelectClause( querySpec.getSelectClause() );
visitFromClause( querySpec.getFromClause() );
visitWhereClause( querySpec );
visitGroupByClause( querySpec, dialect.getGroupBySelectItemReferenceStrategy() );
visitGroupByClause( querySpec, getDialect().getGroupBySelectItemReferenceStrategy() );
visitHavingClause( querySpec );
visitOrderBy( querySpec.getSortSpecifications() );
visitOffsetFetchClause( querySpec );
@ -1681,7 +1708,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
}
else if ( expression instanceof Summarization ) {
Summarization summarization = (Summarization) expression;
appendSql( summarization.getKind().name().toLowerCase() );
appendSql( summarization.getKind().sqlText() );
appendSql( OPEN_PARENTHESIS );
renderCommaSeparated( summarization.getGroupings() );
appendSql( CLOSE_PARENTHESIS );
@ -2093,8 +2120,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
nullPrecedence = sessionFactory.getSessionFactoryOptions().getDefaultNullPrecedence();
}
final boolean renderNullPrecedence = nullPrecedence != null &&
!nullPrecedence.isDefaultOrdering( sortOrder, dialect.getNullOrdering() );
if ( renderNullPrecedence && !dialect.supportsNullPrecedence() ) {
!nullPrecedence.isDefaultOrdering( sortOrder, getDialect().getNullOrdering() );
if ( renderNullPrecedence && !getDialect().supportsNullPrecedence() ) {
emulateSortSpecificationNullPrecedence( sortExpression, nullPrecedence );
}
@ -2112,9 +2139,9 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
appendSql( " desc" );
}
if ( renderNullPrecedence && dialect.supportsNullPrecedence() ) {
if ( renderNullPrecedence && getDialect().supportsNullPrecedence() ) {
appendSql( " nulls " );
appendSql( nullPrecedence.name().toLowerCase( Locale.ROOT ) );
appendSql( nullPrecedence == NullPrecedence.LAST ? "last" : "first" );
}
}
@ -2397,7 +2424,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
renderOffsetExpression( offsetClauseExpression );
if ( offset != 0 ) {
appendSql( '+' );
appendSql( Integer.toString( offset ) );
appendSql( offset );
}
}
@ -2407,7 +2434,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
int offset) {
final Number offsetCount = interpretExpression( offsetClauseExpression, jdbcParameterBindings );
final Number fetchCount = interpretExpression( fetchClauseExpression, jdbcParameterBindings );
appendSql( Integer.toString( fetchCount.intValue() + offsetCount.intValue() + offset ) );
appendSql( fetchCount.intValue() + offsetCount.intValue() + offset );
}
protected void renderFetchPlusOffsetExpressionAsSingleParameter(
@ -2418,7 +2445,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
final Number fetchCount = (Number) ( (Literal) fetchClauseExpression ).getLiteralValue();
if ( offsetClauseExpression instanceof Literal ) {
final Number offsetCount = (Number) ( (Literal) offsetClauseExpression ).getLiteralValue();
appendSql( Integer.toString( fetchCount.intValue() + offsetCount.intValue() + offset ) );
appendSql( fetchCount.intValue() + offsetCount.intValue() + offset );
}
else {
appendSql( PARAM_MARKER );
@ -2653,7 +2680,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
}
}
else {
appendSql( Integer.toString( Integer.MAX_VALUE ) );
appendSql( Integer.MAX_VALUE );
}
}
else if ( fetchExpression != null ) {
@ -2693,7 +2720,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
}
else if ( offsetExpression != null ) {
appendSql( " limit " );
appendSql( Integer.toString( Integer.MAX_VALUE ) );
appendSql( Integer.MAX_VALUE );
}
if ( offsetExpression != null ) {
final Stack<Clause> clauseStack = getClauseStack();
@ -2784,7 +2811,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
appendSql( separator );
appendSql( alias );
appendSql( ".c" );
appendSql( Integer.toString( i ) );
appendSql( i );
separator = COMA_SEPARATOR;
}
}
@ -2944,7 +2971,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
protected void visitSqlSelections(SelectClause selectClause) {
final List<SqlSelection> sqlSelections = selectClause.getSqlSelections();
final int size = sqlSelections.size();
final SelectItemReferenceStrategy referenceStrategy = dialect.getGroupBySelectItemReferenceStrategy();
final SelectItemReferenceStrategy referenceStrategy = getDialect().getGroupBySelectItemReferenceStrategy();
// When the dialect needs to render the aliased expression and there are aliased group by items,
// we need to inline parameters as the database would otherwise not be able to match the group by item
// to the select item, ultimately leading to a query error
@ -2967,7 +2994,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
visitSqlSelection( sqlSelection );
parameterRenderingMode = original;
appendSql( " c" );
appendSql( Integer.toString( i ) );
appendSql( i );
separator = COMA_SEPARATOR;
}
if ( queryPartForRowNumbering != null ) {
@ -3218,9 +3245,10 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
appendSql( "case when " );
expression.accept( this );
appendSql( " then " );
appendSql( getDialect().toBooleanValueString( true ) );
final Dialect dialect = getDialect();
dialect.appendBooleanValueString( this, true );
appendSql( " else " );
appendSql( getDialect().toBooleanValueString( false ) );
dialect.appendBooleanValueString( this, false );
appendSql( " end" );
}
else {
@ -3290,12 +3318,11 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
}
}
else {
appendSql(
literalFormatter.toJdbcLiteral(
literalFormatter.appendJdbcLiteral(
this,
literal.getLiteralValue(),
dialect,
getWrapperOptions()
)
);
}
}
@ -3557,9 +3584,8 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
@Override
public void visitFormat(Format format) {
final String dialectFormat = getDialect().translateDatetimeFormat( format.getFormat() );
appendSql( '\'' );
appendSql( dialectFormat );
getDialect().appendDatetimeFormat( this, format.getFormat() );
appendSql( '\'' );
}
@ -3680,297 +3706,16 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
@Override
public void visitSqlSelectionExpression(SqlSelectionExpression expression) {
final boolean useSelectionPosition = dialect.supportsOrdinalSelectItemReference();
final boolean useSelectionPosition = getDialect().supportsOrdinalSelectItemReference();
if ( useSelectionPosition ) {
appendSql( Integer.toString( expression.getSelection().getJdbcResultSetIndex() ) );
appendSql( expression.getSelection().getJdbcResultSetIndex() );
}
else {
expression.getSelection().getExpression().accept( this );
}
}
// // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// // Expression : Function : Non-Standard
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitNonStandardFunctionExpression(NonStandardFunction function) {
// appendSql( function.getFunctionName() );
// if ( !function.getArguments().isEmpty() ) {
// appendSql( OPEN_PARENTHESIS );
// String separator = NO_SEPARATOR;
// for ( Expression argumentExpression : function.getArguments() ) {
// appendSql( separator );
// argumentExpression.accept( this );
// separator = COMA_SEPARATOR;
// }
// appendSql( CLOSE_PARENTHESIS );
// }
// }
//
//
// // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// // Expression : Function : Standard
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitAbsFunction(AbsFunction function) {
// appendSql( "abs(" );
// function.getArgument().accept( this );
// appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitAvgFunction(AvgFunction function) {
// appendSql( "avg(" );
// function.getArgument().accept( this );
// appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitBitLengthFunction(BitLengthFunction function) {
// appendSql( "bit_length(" );
// function.getArgument().accept( this );
// appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitCastFunction(CastFunction function) {
// sqlAppender.appendSql( "cast(" );
// function.getExpressionToCast().accept( this );
// sqlAppender.appendSql( AS_KEYWORD );
// sqlAppender.appendSql( determineCastTargetTypeSqlExpression( function ) );
// sqlAppender.appendSql( CLOSE_PARENTHESIS );
// }
//
// private String determineCastTargetTypeSqlExpression(CastFunction castFunction) {
// if ( castFunction.getExplicitCastTargetTypeSqlExpression() != null ) {
// return castFunction.getExplicitCastTargetTypeSqlExpression();
// }
//
// final SqlExpressableType castResultType = castFunction.getCastResultType();
//
// if ( castResultType == null ) {
// throw new SqlTreeException(
// "CastFunction did not define an explicit cast target SQL expression and its return type was null"
// );
// }
//
// final BasicJavaDescriptor javaTypeDescriptor = castResultType.getJavaTypeDescriptor();
// return getJdbcServices()
// .getDialect()
// .getCastTypeName( javaTypeDescriptor.getJdbcRecommendedSqlType( this ).getJdbcTypeCode() );
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitConcatFunction(ConcatFunction function) {
// appendSql( "concat(" );
//
// boolean firstPass = true;
// for ( Expression expression : function.getExpressions() ) {
// if ( ! firstPass ) {
// appendSql( COMA_SEPARATOR );
// }
// expression.accept( this );
// firstPass = false;
// }
//
// appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitSubstrFunction(SubstrFunction function) {
// appendSql( "substr(" );
//
// boolean firstPass = true;
// for ( Expression expression : function.getExpressions() ) {
// if ( ! firstPass ) {
// appendSql( COMA_SEPARATOR );
// }
// expression.accept( this );
// firstPass = false;
// }
//
// appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitCountFunction(CountFunction function) {
// appendSql( "count(" );
// if ( function.isDistinct() ) {
// appendSql( DISTINCT_KEYWORD );
// }
// function.getArgument().accept( this );
// appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// public void visitCountStarFunction(CountStarFunction function) {
// appendSql( "count(" );
// if ( function.isDistinct() ) {
// appendSql( DISTINCT_KEYWORD );
// }
// appendSql( "*)" );
// }
//
// @Override
// public void visitCurrentDateFunction(CurrentDateFunction function) {
// appendSql( "current_date" );
// }
//
// @Override
// public void visitCurrentTimeFunction(CurrentTimeFunction function) {
// appendSql( "current_time" );
// }
//
// @Override
// public void visitCurrentTimestampFunction(CurrentTimestampFunction function) {
// appendSql( "current_timestamp" );
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitExtractFunction(ExtractFunction extractFunction) {
// appendSql( "extract(" );
// extractFunction.getUnitToExtract().accept( this );
// appendSql( FROM_KEYWORD );
// extractFunction.getExtractionSource().accept( this );
// appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitLengthFunction(LengthFunction function) {
// sqlAppender.appendSql( "length(" );
// function.getArgument().accept( this );
// sqlAppender.appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitLocateFunction(LocateFunction function) {
// appendSql( "locate(" );
// function.getPatternString().accept( this );
// appendSql( COMA_SEPARATOR );
// function.getStringToSearch().accept( this );
// if ( function.getStartPosition() != null ) {
// appendSql( COMA_SEPARATOR );
// function.getStartPosition().accept( this );
// }
// appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitLowerFunction(LowerFunction function) {
// appendSql( "lower(" );
// function.getArgument().accept( this );
// appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitMaxFunction(MaxFunction function) {
// appendSql( "max(" );
// if ( function.isDistinct() ) {
// appendSql( DISTINCT_KEYWORD );
// }
// function.getArgument().accept( this );
// appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitMinFunction(MinFunction function) {
// appendSql( "min(" );
// if ( function.isDistinct() ) {
// appendSql( DISTINCT_KEYWORD );
// }
// function.getArgument().accept( this );
// appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitModFunction(ModFunction function) {
// sqlAppender.appendSql( "mod(" );
// function.getDividend().accept( this );
// sqlAppender.appendSql( COMA_SEPARATOR );
// function.getDivisor().accept( this );
// sqlAppender.appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitSqrtFunction(SqrtFunction function) {
// appendSql( "sqrt(" );
// function.getArgument().accept( this );
// appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitSumFunction(SumFunction function) {
// appendSql( "sum(" );
// if ( function.isDistinct() ) {
// appendSql( DISTINCT_KEYWORD );
// }
// function.getArgument().accept( this );
// appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitTrimFunction(TrimFunction function) {
// sqlAppender.appendSql( "trim(" );
// sqlAppender.appendSql( function.getSpecification().toSqlText() );
// sqlAppender.appendSql( EMPTY_STRING_SEPARATOR );
// function.getTrimCharacter().accept( this );
// sqlAppender.appendSql( FROM_KEYWORD );
// function.getSource().accept( this );
// sqlAppender.appendSql( CLOSE_PARENTHESIS );
//
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public void visitUpperFunction(UpperFunction function) {
// appendSql( "upper(" );
// function.getArgument().accept( this );
// appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// public void visitCoalesceFunction(CoalesceFunction coalesceExpression) {
// appendSql( "coalesce(" );
// String separator = NO_SEPARATOR;
// for ( Expression expression : coalesceExpression.getValues() ) {
// appendSql( separator );
// expression.accept( this );
// separator = COMA_SEPARATOR;
// }
//
// appendSql( CLOSE_PARENTHESIS );
// }
//
// @Override
// public void visitNullifFunction(NullifFunction function) {
// appendSql( "nullif(" );
// function.getFirstArgument().accept( this );
// appendSql( COMA_SEPARATOR );
// function.getSecondArgument().accept( this );
// appendSql( CLOSE_PARENTHESIS );
// }
@Override
public void visitEntityTypeLiteral(EntityTypeLiteral expression) {
final EntityPersister entityTypeDescriptor = expression.getEntityTypeDescriptor();
@ -4179,7 +3924,6 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
private void visitLiteral(Literal literal) {
if ( literal.getLiteralValue() == null ) {
// todo : not sure we allow this "higher up"
appendSql( SqlAppender.NULL_KEYWORD );
}
else {
@ -4199,12 +3943,11 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
throw new IllegalArgumentException( "Can't render parameter as literal, no literal formatter found" );
}
else {
appendSql(
literalFormatter.toJdbcLiteral(
literalFormatter.appendJdbcLiteral(
this,
literalValue,
dialect,
getWrapperOptions()
)
);
}
}
@ -4248,7 +3991,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
// Most databases do not support boolean expressions in a predicate context, so we render `expr=true`
booleanExpressionPredicate.getExpression().accept( this );
appendSql( '=' );
appendSql( getDialect().toBooleanValueString( true ) );
getDialect().appendBooleanValueString( this, true );
}
@Override
@ -4314,7 +4057,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
ComparisonOperator.NOT_EQUAL :
ComparisonOperator.EQUAL;
// Some DBs like Oracle support tuples only for the IN subquery predicate
if ( supportsRowValueConstructorSyntaxInInSubQuery() && dialect.supportsUnionAll() ) {
if ( supportsRowValueConstructorSyntaxInInSubQuery() && getDialect().supportsUnionAll() ) {
inListPredicate.getTestExpression().accept( this );
if ( inListPredicate.isNegated() ) {
appendSql( " not" );
@ -4527,7 +4270,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
visitSelectClause( subQuery.getSelectClause() );
visitFromClause( subQuery.getFromClause() );
visitWhereClause( subQuery );
visitGroupByClause( subQuery, dialect.getGroupBySelectItemReferenceStrategy() );
visitGroupByClause( subQuery, getDialect().getGroupBySelectItemReferenceStrategy() );
visitHavingClause( subQuery );
appendSql( " order by " );
@ -4544,7 +4287,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
appendSql( order );
for ( int i = 1; i < sqlSelections.size(); i++ ) {
appendSql( COMA_SEPARATOR_CHAR );
appendSql( Integer.toString( i + 1 ) );
appendSql( i + 1 );
appendSql( order );
}
renderFetch( ONE_LITERAL, null, FetchClauseType.ROWS_ONLY );
@ -4613,13 +4356,13 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
}
}
else {
if (dialect.supportsCaseInsensitiveLike()) {
if (getDialect().supportsCaseInsensitiveLike()) {
likePredicate.getMatchExpression().accept( this );
if ( likePredicate.isNegated() ) {
appendSql( " not" );
}
appendSql( WHITESPACE );
appendSql( dialect.getCaseInsensitiveLike() );
appendSql( getDialect().getCaseInsensitiveLike() );
appendSql( WHITESPACE );
likePredicate.getPattern().accept( this );
if ( likePredicate.getEscapeCharacter() != null ) {
@ -4637,7 +4380,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
protected void renderCaseInsensitiveLikeEmulation(Expression lhs, Expression rhs, Expression escapeCharacter, boolean negated) {
//LOWER(lhs) operator LOWER(rhs)
appendSql( dialect.getLowercaseFunction() );
appendSql( getDialect().getLowercaseFunction() );
appendSql( OPEN_PARENTHESIS );
lhs.accept( this );
appendSql( CLOSE_PARENTHESIS );
@ -4645,7 +4388,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
appendSql( " not" );
}
appendSql( " like " );
appendSql( dialect.getLowercaseFunction() );
appendSql( getDialect().getLowercaseFunction() );
appendSql( OPEN_PARENTHESIS );
rhs.accept( this );
appendSql( CLOSE_PARENTHESIS );

View File

@ -6,12 +6,14 @@
*/
package org.hibernate.sql.ast.spi;
import java.io.IOException;
/**
* Access to appending SQL fragments to an in-flight buffer
*
* @author Steve Ebersole
*/
public interface SqlAppender {
public interface SqlAppender extends Appendable {
String NO_SEPARATOR = "";
String COMA_SEPARATOR = ",";
char COMA_SEPARATOR_CHAR = ',';
@ -29,17 +31,31 @@ public interface SqlAppender {
*/
void appendSql(String fragment);
void appendSql(char fragment);
default void appendSql(char fragment) {
appendSql( Character.toString( fragment ) );
}
default void appendQuoted(String value, char quoteChar) {
appendSql( quoteChar );
for ( int i = 0; i < value.length(); i++ ) {
final char c = value.charAt( i );
if ( c == quoteChar ) {
appendSql( quoteChar );
default void appendSql(int value) {
appendSql( Integer.toString( value ) );
}
appendSql( c );
default void appendSql(boolean value) {
appendSql( String.valueOf( value ) );
}
appendSql( quoteChar );
default Appendable append(CharSequence csq) {
appendSql( csq.toString() );
return this;
}
default Appendable append(CharSequence csq, int start, int end) {
appendSql( csq.toString().substring( start, end ) );
return this;
}
default Appendable append(char c) {
appendSql( Character.toString( c ) );
return this;
}
}

View File

@ -43,7 +43,17 @@ public class Summarization implements Expression {
}
public enum Kind {
ROLLUP,
CUBE
ROLLUP( "rollup" ),
CUBE( "cube" );
private final String sqlText;
Kind(String sqlText) {
this.sqlText = sqlText;
}
public String sqlText() {
return sqlText;
}
}
}

View File

@ -13,9 +13,13 @@ import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import org.hibernate.sql.ast.spi.SqlAppender;
import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE;
import static java.time.format.DateTimeFormatter.ISO_LOCAL_TIME;
@ -71,8 +75,8 @@ public final class DateTimeUtils {
.optionalStart().appendZoneOrOffsetId().optionalEnd()
.toFormatter();
private static final ThreadLocal<SimpleDateFormat> LOCAL_DATE_FORMAT = ThreadLocal.withInitial( DateTimeUtils::simpleDateFormatDate );
private static final ThreadLocal<SimpleDateFormat> LOCAL_TIME_FORMAT = ThreadLocal.withInitial( DateTimeUtils::simpleDateFormatTime );
private static final ThreadLocal<SimpleDateFormat> LOCAL_DATE_FORMAT = ThreadLocal.withInitial( () -> new SimpleDateFormat( FORMAT_STRING_DATE, Locale.ENGLISH ) );
private static final ThreadLocal<SimpleDateFormat> LOCAL_TIME_FORMAT = ThreadLocal.withInitial( () -> new SimpleDateFormat( FORMAT_STRING_TIME, Locale.ENGLISH ) );
private static final ThreadLocal<SimpleDateFormat> TIMESTAMP_WITH_MILLIS_FORMAT = ThreadLocal.withInitial(
() -> new SimpleDateFormat(
FORMAT_STRING_TIMESTAMP_WITH_MILLIS,
@ -103,201 +107,163 @@ public final class DateTimeUtils {
.appendOffset("+HH:mm", "+00")
.toFormatter();
public static String formatAsTimestampWithMicros(TemporalAccessor temporalAccessor, boolean supportsOffset, TimeZone jdbcTimeZone) {
public static void appendAsTimestampWithMicros(
SqlAppender appender,
TemporalAccessor temporalAccessor,
boolean supportsOffset,
TimeZone jdbcTimeZone) {
if ( temporalAccessor.isSupported(ChronoField.OFFSET_SECONDS) ) {
if ( supportsOffset ) {
return DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS_AND_OFFSET.format( temporalAccessor );
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS_AND_OFFSET.formatTo( temporalAccessor, appender );
}
else {
return DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS.format(
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS.formatTo(
LocalDateTime.ofInstant(
Instant.from( temporalAccessor ),
jdbcTimeZone.toZoneId()
)
),
appender
);
}
}
else {
return DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS.format( temporalAccessor );
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS.formatTo( temporalAccessor, appender );
}
}
public static String formatAsTimestampWithMillis(TemporalAccessor temporalAccessor, boolean supportsOffset, TimeZone jdbcTimeZone) {
public static void appendAsTimestampWithMillis(
SqlAppender appender,
TemporalAccessor temporalAccessor,
boolean supportsOffset,
TimeZone jdbcTimeZone) {
if ( temporalAccessor.isSupported(ChronoField.OFFSET_SECONDS) ) {
if ( supportsOffset ) {
return DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS_AND_OFFSET.format( temporalAccessor );
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS_AND_OFFSET.formatTo( temporalAccessor, appender );
}
else {
return DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS.format(
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS.formatTo(
LocalDateTime.ofInstant(
Instant.from( temporalAccessor ),
jdbcTimeZone.toZoneId()
)
),
appender
);
}
}
else {
return DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS.format( temporalAccessor );
DATE_TIME_FORMATTER_TIMESTAMP_WITH_MILLIS.formatTo( temporalAccessor, appender );
}
}
public static String formatAsDate(TemporalAccessor temporalAccessor) {
return DATE_TIME_FORMATTER_DATE.format( temporalAccessor );
public static void appendAsDate(SqlAppender appender, TemporalAccessor temporalAccessor) {
DATE_TIME_FORMATTER_DATE.formatTo( temporalAccessor, appender );
}
public static String formatAsTime(TemporalAccessor temporalAccessor, boolean supportsOffset, TimeZone jdbcTimeZone) {
public static void appendAsTime(
SqlAppender appender,
TemporalAccessor temporalAccessor,
boolean supportsOffset,
TimeZone jdbcTimeZone) {
if ( temporalAccessor.isSupported(ChronoField.OFFSET_SECONDS) ) {
if ( supportsOffset ) {
return DATE_TIME_FORMATTER_TIME_WITH_OFFSET.format( temporalAccessor );
DATE_TIME_FORMATTER_TIME_WITH_OFFSET.formatTo( temporalAccessor, appender );
}
else {
return DATE_TIME_FORMATTER_TIME.format(
DATE_TIME_FORMATTER_TIME.formatTo(
LocalDateTime.ofInstant(
Instant.from( temporalAccessor ),
jdbcTimeZone.toZoneId()
)
),
appender
);
}
}
else {
return DATE_TIME_FORMATTER_TIME.format( temporalAccessor );
DATE_TIME_FORMATTER_TIME.formatTo( temporalAccessor, appender );
}
}
public static String formatAsTimestampWithMillis(java.util.Date date, TimeZone jdbcTimeZone) {
public static void appendAsTimestampWithMillis(SqlAppender appender, java.util.Date date, TimeZone jdbcTimeZone) {
final SimpleDateFormat simpleDateFormat = TIMESTAMP_WITH_MILLIS_FORMAT.get();
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
try {
simpleDateFormat.setTimeZone( jdbcTimeZone );
return simpleDateFormat.format( date );
appender.appendSql( simpleDateFormat.format( date ) );
}
finally {
simpleDateFormat.setTimeZone( originalTimeZone );
}
}
public static String formatAsTimestampWithMicros(java.util.Date date, TimeZone jdbcTimeZone) {
public static void appendAsTimestampWithMicros(SqlAppender appender, Date date, TimeZone jdbcTimeZone) {
final SimpleDateFormat simpleDateFormat = TIMESTAMP_WITH_MICROS_FORMAT.get();
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
try {
simpleDateFormat.setTimeZone( jdbcTimeZone );
return simpleDateFormat.format( date );
appender.appendSql( simpleDateFormat.format( date ) );
}
finally {
simpleDateFormat.setTimeZone( originalTimeZone );
}
}
public static String wrapAsJdbcDateLiteral(String literal) {
return JDBC_ESCAPE_START_DATE + literal + JDBC_ESCAPE_END;
public static void appendAsDate(SqlAppender appender, Date date) {
appender.appendSql( LOCAL_DATE_FORMAT.get().format( date ) );
}
public static String wrapAsJdbcTimeLiteral(String literal) {
return JDBC_ESCAPE_START_TIME + literal + JDBC_ESCAPE_END;
public static void appendAsTime(SqlAppender appender, java.util.Date date) {
appender.appendSql( LOCAL_TIME_FORMAT.get().format( date ) );
}
public static String wrapAsJdbcTimestampLiteral(String literal) {
return JDBC_ESCAPE_START_TIMESTAMP + literal + JDBC_ESCAPE_END;
}
public static String wrapAsAnsiDateLiteral(String literal) {
return "date '" + literal + "'";
}
public static String wrapAsAnsiTimeLiteral(String literal) {
return "time '" + literal + "'";
}
public static String wrapAsAnsiTimestampLiteral(String literal) {
return "timestamp '" + literal + "'";
}
public static String formatAsDate(java.util.Date date) {
return LOCAL_DATE_FORMAT.get().format( date );
}
public static SimpleDateFormat simpleDateFormatDate() {
return new SimpleDateFormat( FORMAT_STRING_DATE, Locale.ENGLISH );
}
public static String formatAsTime(java.util.Date date) {
return LOCAL_TIME_FORMAT.get().format( date );
}
public static SimpleDateFormat simpleDateFormatTime() {
return new SimpleDateFormat( FORMAT_STRING_TIME, Locale.ENGLISH );
}
public static String formatAsTimestampWithMillis(java.util.Calendar calendar, TimeZone jdbcTimeZone) {
public static void appendAsTimestampWithMillis(
SqlAppender appender,
java.util.Calendar calendar,
TimeZone jdbcTimeZone) {
final SimpleDateFormat simpleDateFormat = TIMESTAMP_WITH_MILLIS_FORMAT.get();
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
try {
simpleDateFormat.setTimeZone( jdbcTimeZone );
return simpleDateFormat.format( calendar.getTime() );
appender.appendSql( simpleDateFormat.format( calendar.getTime() ) );
}
finally {
simpleDateFormat.setTimeZone( originalTimeZone );
}
}
public static SimpleDateFormat simpleDateFormatTimestampWithMillis(TimeZone timeZone) {
final SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_STRING_TIMESTAMP_WITH_MILLIS, Locale.ENGLISH );
formatter.setTimeZone( timeZone );
return formatter;
}
public static String formatAsTimestampWithMicros(java.util.Calendar calendar, TimeZone jdbcTimeZone) {
public static void appendAsTimestampWithMicros(SqlAppender appender, Calendar calendar, TimeZone jdbcTimeZone) {
final SimpleDateFormat simpleDateFormat = TIMESTAMP_WITH_MICROS_FORMAT.get();
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
try {
simpleDateFormat.setTimeZone( jdbcTimeZone );
return simpleDateFormat.format( calendar.getTime() );
appender.appendSql( simpleDateFormat.format( calendar.getTime() ) );
}
finally {
simpleDateFormat.setTimeZone( originalTimeZone );
}
}
public static SimpleDateFormat simpleDateFormatTimestampWithMicros(TimeZone timeZone) {
final SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_STRING_TIMESTAMP_WITH_MICROS, Locale.ENGLISH );
formatter.setTimeZone( timeZone );
return formatter;
}
public static String formatAsDate(java.util.Calendar calendar) {
public static void appendAsDate(SqlAppender appender, java.util.Calendar calendar) {
final SimpleDateFormat simpleDateFormat = LOCAL_DATE_FORMAT.get();
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
try {
simpleDateFormat.setTimeZone( calendar.getTimeZone() );
return simpleDateFormat.format( calendar.getTime() );
appender.appendSql( simpleDateFormat.format( calendar.getTime() ) );
}
finally {
simpleDateFormat.setTimeZone( originalTimeZone );
}
}
public static SimpleDateFormat simpleDateFormatDate(TimeZone timeZone) {
final SimpleDateFormat formatter = new SimpleDateFormat( FORMAT_STRING_DATE, Locale.ENGLISH );
formatter.setTimeZone( timeZone );
return formatter;
}
public static String formatAsTime(java.util.Calendar calendar) {
public static void appendAsTime(SqlAppender appender, java.util.Calendar calendar) {
final SimpleDateFormat simpleDateFormat = LOCAL_TIME_FORMAT.get();
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
try {
simpleDateFormat.setTimeZone( calendar.getTimeZone() );
return simpleDateFormat.format( calendar.getTime() );
appender.appendSql( simpleDateFormat.format( calendar.getTime() ) );
}
finally {
simpleDateFormat.setTimeZone( originalTimeZone );
}
}
public static SimpleDateFormat simpleDateFormatTime(TimeZone timeZone) {
final SimpleDateFormat formatter = new SimpleDateFormat( FORMAT_STRING_TIME, Locale.ENGLISH );
formatter.setTimeZone( timeZone );
return formatter;
}
}

View File

@ -16,6 +16,7 @@ import java.util.Comparator;
import org.hibernate.HibernateException;
import org.hibernate.engine.jdbc.BinaryStream;
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.type.descriptor.WrapperOptions;
/**
@ -48,14 +49,18 @@ public class PrimitiveByteArrayTypeDescriptor extends AbstractClassTypeDescripto
public String toString(byte[] bytes) {
final StringBuilder buf = new StringBuilder( bytes.length * 2 );
appendString( buf::append, bytes );
return buf.toString();
}
public void appendString(SqlAppender appender, byte[] bytes) {
for ( byte aByte : bytes ) {
final String hexStr = Integer.toHexString( Byte.toUnsignedInt(aByte) );
if ( hexStr.length() == 1 ) {
buf.append( '0' );
appender.appendSql( '0' );
}
buf.append( hexStr );
appender.appendSql( hexStr );
}
return buf.toString();
}
@Override

View File

@ -7,6 +7,7 @@
package org.hibernate.type.descriptor.jdbc;
import org.hibernate.dialect.Dialect;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.type.descriptor.WrapperOptions;
/**
@ -24,5 +25,11 @@ import org.hibernate.type.descriptor.WrapperOptions;
public interface JdbcLiteralFormatter<T> {
String NULL = "null";
String toJdbcLiteral(T value, Dialect dialect, WrapperOptions wrapperOptions);
default String toJdbcLiteral(T value, Dialect dialect, WrapperOptions wrapperOptions) {
final StringBuilder sb = new StringBuilder();
appendJdbcLiteral( sb::append, value, dialect, wrapperOptions );
return sb.toString();
}
void appendJdbcLiteral(SqlAppender appender, T value, Dialect dialect, WrapperOptions wrapperOptions);
}

View File

@ -79,7 +79,7 @@ public interface JdbcTypeDescriptor extends Serializable {
* todo (6.0) : move to {@link org.hibernate.metamodel.mapping.JdbcMapping}?
*/
default <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
return (value, dialect, wrapperOptions) -> value.toString();
return (appender, value, dialect, wrapperOptions) -> appender.appendSql( value.toString() );
}
/**

View File

@ -7,6 +7,7 @@
package org.hibernate.type.descriptor.jdbc.internal;
import org.hibernate.dialect.Dialect;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.BasicJdbcLiteralFormatter;
@ -17,12 +18,12 @@ import org.hibernate.type.descriptor.jdbc.spi.BasicJdbcLiteralFormatter;
* @author Gavin King
*/
public class JdbcLiteralFormatterBinary extends BasicJdbcLiteralFormatter {
public JdbcLiteralFormatterBinary(JavaTypeDescriptor javaTypeDescriptor) {
public JdbcLiteralFormatterBinary(JavaTypeDescriptor<?> javaTypeDescriptor) {
super( javaTypeDescriptor );
}
@Override
public String toJdbcLiteral(Object value, Dialect dialect, WrapperOptions wrapperOptions) {
return dialect.formatBinaryLiteral( unwrap( value, byte[].class, wrapperOptions ) );
public void appendJdbcLiteral(SqlAppender appender, Object value, Dialect dialect, WrapperOptions wrapperOptions) {
dialect.appendBinaryLiteral( appender, unwrap( value, byte[].class, wrapperOptions ) );
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.type.descriptor.jdbc.internal;
import org.hibernate.dialect.Dialect;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.BasicJdbcLiteralFormatter;
@ -17,12 +18,12 @@ import org.hibernate.type.descriptor.jdbc.spi.BasicJdbcLiteralFormatter;
* @author Steve Ebersole
*/
public class JdbcLiteralFormatterBoolean extends BasicJdbcLiteralFormatter {
public JdbcLiteralFormatterBoolean(JavaTypeDescriptor javaTypeDescriptor) {
public JdbcLiteralFormatterBoolean(JavaTypeDescriptor<?> javaTypeDescriptor) {
super( javaTypeDescriptor );
}
@Override
public String toJdbcLiteral(Object value, Dialect dialect, WrapperOptions wrapperOptions) {
return dialect.toBooleanValueString( unwrap( value, Boolean.class, wrapperOptions ) );
public void appendJdbcLiteral(SqlAppender appender, Object value, Dialect dialect, WrapperOptions wrapperOptions) {
dialect.appendBooleanValueString( appender, unwrap( value, Boolean.class, wrapperOptions ) );
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.type.descriptor.jdbc.internal;
import org.hibernate.dialect.Dialect;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.BasicJdbcLiteralFormatter;
@ -21,26 +22,21 @@ public class JdbcLiteralFormatterCharacterData extends BasicJdbcLiteralFormatter
private final boolean isNationalized;
public JdbcLiteralFormatterCharacterData(JavaTypeDescriptor javaTypeDescriptor) {
public JdbcLiteralFormatterCharacterData(JavaTypeDescriptor<?> javaTypeDescriptor) {
this( javaTypeDescriptor, false );
}
public JdbcLiteralFormatterCharacterData(JavaTypeDescriptor javaTypeDescriptor, boolean isNationalized) {
public JdbcLiteralFormatterCharacterData(JavaTypeDescriptor<?> javaTypeDescriptor, boolean isNationalized) {
super( javaTypeDescriptor );
this.isNationalized = isNationalized;
}
@Override
public String toJdbcLiteral(Object value, Dialect dialect, WrapperOptions wrapperOptions) {
public void appendJdbcLiteral(SqlAppender appender, Object value, Dialect dialect, WrapperOptions wrapperOptions) {
final String literalValue = unwrap( value, String.class, wrapperOptions );
final String inlineLiteral = dialect.inlineLiteral( literalValue );
if ( isNationalized ) {
// is there a standardized form for n-string literals? This is the SQL Server syntax for sure
return NATIONALIZED_PREFIX.concat( inlineLiteral );
appender.appendSql( NATIONALIZED_PREFIX );
}
return inlineLiteral;
dialect.appendLiteral( appender, literalValue );
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.type.descriptor.jdbc.internal;
import org.hibernate.dialect.Dialect;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.BasicJdbcLiteralFormatter;
@ -18,14 +19,14 @@ public class JdbcLiteralFormatterNumericData extends BasicJdbcLiteralFormatter {
private final Class<? extends Number> unwrapJavaType;
public JdbcLiteralFormatterNumericData(
JavaTypeDescriptor javaTypeDescriptor,
JavaTypeDescriptor<?> javaTypeDescriptor,
Class<? extends Number> unwrapJavaType) {
super( javaTypeDescriptor );
this.unwrapJavaType = unwrapJavaType;
}
@Override
public String toJdbcLiteral(Object value, Dialect dialect, WrapperOptions wrapperOptions) {
return unwrap( value, unwrapJavaType, wrapperOptions ).toString();
public void appendJdbcLiteral(SqlAppender appender, Object value, Dialect dialect, WrapperOptions wrapperOptions) {
appender.appendSql( unwrap( value, unwrapJavaType, wrapperOptions ).toString() );
}
}

View File

@ -11,6 +11,7 @@ import java.util.TimeZone;
import jakarta.persistence.TemporalType;
import org.hibernate.dialect.Dialect;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.BasicJdbcLiteralFormatter;
@ -21,13 +22,13 @@ import org.hibernate.type.descriptor.jdbc.spi.BasicJdbcLiteralFormatter;
public class JdbcLiteralFormatterTemporal extends BasicJdbcLiteralFormatter {
private final TemporalType precision;
public JdbcLiteralFormatterTemporal(JavaTypeDescriptor javaTypeDescriptor, TemporalType precision) {
public JdbcLiteralFormatterTemporal(JavaTypeDescriptor<?> javaTypeDescriptor, TemporalType precision) {
super( javaTypeDescriptor );
this.precision = precision;
}
@Override
public String toJdbcLiteral(Object value, Dialect dialect, WrapperOptions wrapperOptions) {
public void appendJdbcLiteral(SqlAppender appender, Object value, Dialect dialect, WrapperOptions wrapperOptions) {
final TimeZone jdbcTimeZone;
if ( wrapperOptions == null || wrapperOptions.getJdbcTimeZone() == null ) {
jdbcTimeZone = TimeZone.getDefault();
@ -37,48 +38,55 @@ public class JdbcLiteralFormatterTemporal extends BasicJdbcLiteralFormatter {
}
// for performance reasons, avoid conversions if we can
if ( value instanceof java.util.Date ) {
return dialect.formatDateTimeLiteral(
dialect.appendDateTimeLiteral(
appender,
(java.util.Date) value,
precision,
jdbcTimeZone
);
}
else if ( value instanceof java.util.Calendar ) {
return dialect.formatDateTimeLiteral(
dialect.appendDateTimeLiteral(
appender,
(java.util.Calendar) value,
precision,
jdbcTimeZone
);
}
else if ( value instanceof TemporalAccessor ) {
return dialect.formatDateTimeLiteral(
dialect.appendDateTimeLiteral(
appender,
(TemporalAccessor) value,
precision,
jdbcTimeZone
);
}
switch ( precision) {
case DATE: {
return dialect.formatDateTimeLiteral(
else {
switch ( precision ) {
case DATE:
dialect.appendDateTimeLiteral(
appender,
unwrap( value, java.sql.Date.class, wrapperOptions ),
precision,
jdbcTimeZone
);
}
case TIME: {
return dialect.formatDateTimeLiteral(
break;
case TIME:
dialect.appendDateTimeLiteral(
appender,
unwrap( value, java.sql.Time.class, wrapperOptions ),
precision,
jdbcTimeZone
);
}
default: {
return dialect.formatDateTimeLiteral(
break;
default:
dialect.appendDateTimeLiteral(
appender,
unwrap( value, java.util.Date.class, wrapperOptions ),
precision,
jdbcTimeZone
);
break;
}
}
}

View File

@ -354,7 +354,7 @@ public class TypeConfiguration implements SessionFactoryObserver, Serializable {
private String sessionFactoryName;
private String sessionFactoryUuid;
private transient JdbcTypeDescriptorIndicators currentSqlTypeIndicators = new JdbcTypeDescriptorIndicators() {
private final transient JdbcTypeDescriptorIndicators currentSqlTypeIndicators = new JdbcTypeDescriptorIndicators() {
@Override
public TypeConfiguration getTypeConfiguration() {
return typeConfiguration;

View File

@ -52,9 +52,17 @@ public class PGGeometryTypeDescriptor implements JdbcTypeDescriptor {
@Override
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
if ( javaTypeDescriptor instanceof GeolatteGeometryJavaTypeDescriptor ) {
return (value, dialect, wrapperOptions) -> "ST_GeomFromEWKT('" + value + "')";
return (appender, value, dialect, wrapperOptions) -> {
appender.appendSql( "ST_GeomFromEWKT('" );
appender.appendSql( value.toString() );
appender.appendSql( "')" );
};
}
return (value, dialect, wrapperOptions) -> "ST_GeomFromEWKT('" + jts2Gl( value ) + "')";
return (appender, value, dialect, wrapperOptions) -> {
appender.appendSql( "ST_GeomFromEWKT('" );
appender.appendSql( jts2Gl( value ).toString() );
appender.appendSql( "')" );
};
}
private <T> Geometry<?> jts2Gl(T value) {

View File

@ -334,7 +334,7 @@ abstract public class DialectFeatureChecks {
public static class SupportsFormat implements DialectFeatureCheck {
public boolean apply(Dialect dialect) {
try {
dialect.translateDatetimeFormat( "" );
dialect.appendDatetimeFormat( new StringBuilder()::append, "" );
return true;
}
catch (Exception ex) {
@ -346,7 +346,7 @@ abstract public class DialectFeatureChecks {
public static class SupportsTruncateThroughCast implements DialectFeatureCheck {
public boolean apply(Dialect dialect) {
try {
dialect.translateDatetimeFormat( "" );
dialect.appendDatetimeFormat( new StringBuilder()::append, "" );
return true;
}
catch (Exception ex) {