Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion documentation/src/main/asciidoc/querylanguage/Expressions.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1495,7 +1495,7 @@ Their syntax is defined by:
include::{extrasdir}/predicate_like_bnf.txt[]
----

The expression on the right is a pattern, where:
The expression on the right is usually a SQL-style pattern, where:

* `_` matches any single character,
* `%` matches any number of characters, and
Expand All @@ -1509,6 +1509,14 @@ from Book where title not like '% for Dummies'

The optional `escape` character allows a pattern to include a literal `_` or `%` character.

Alternatively, the `regexp` keyword specifies that the pattern should be interpreted as a regular expression:

[[like-regexp-predicate-example]]
[source, hql]
----
from Book where title not like regexp '.+ for Dummies'
----

As you can guess, `not like` and `not ilike` are the enemies of `like` and `ilike`, and evaluate to the exact opposite boolean values.

[[in-predicate]]
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
expression "NOT"? ("LIKE" | "ILIKE") expression ("ESCAPE" character)?
expression "NOT"? ("LIKE" | "ILIKE") REGEXP? expression ("ESCAPE" character)?
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ POSITION : [pP] [oO] [sS] [iI] [tT] [iI] [oO] [nN];
PRECEDING : [pP] [rR] [eE] [cC] [eE] [dD] [iI] [nN] [gG];
QUARTER : [qQ] [uU] [aA] [rR] [tT] [eE] [rR];
RANGE : [rR] [aA] [nN] [gG] [eE];
REGEXP : [rR] [eE] [gG] [eE] [xX] [pP];
RESPECT : [rR] [eE] [sS] [pP] [eE] [cC] [tT];
RETURNING : [rR] [eE] [tT] [uU] [rR] [nN] [iI] [nN] [gG];
RIGHT : [rR] [iI] [gG] [hH] [tT];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,7 @@ predicate
| expression NOT? MEMBER OF? path # MemberOfPredicate
| expression NOT? IN inList # InPredicate
| expression NOT? BETWEEN expression AND expression # BetweenPredicate
| expression NOT? (LIKE | ILIKE) expression likeEscape? # LikePredicate
| expression NOT? (LIKE | ILIKE) REGEXP? expression likeEscape? # LikePredicate
| expression NOT? CONTAINS expression # ContainsPredicate
| expression NOT? INCLUDES expression # IncludesPredicate
| expression NOT? INTERSECTS expression # IntersectsPredicate
Expand Down Expand Up @@ -1998,6 +1998,7 @@ xmltableDefaultClause
| PRECEDING
| QUARTER
| RANGE
| REGEXP
| RESPECT
| RETURNING
// | RIGHT
Expand Down
71 changes: 36 additions & 35 deletions hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@
import org.hibernate.tool.schema.spi.SchemaManagementTool;
import org.hibernate.tool.schema.spi.TableMigrator;
import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeRegistry;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.WrapperOptions;
Expand Down Expand Up @@ -235,7 +234,6 @@
import static org.hibernate.type.SqlTypes.BIGINT;
import static org.hibernate.type.SqlTypes.BINARY;
import static org.hibernate.type.SqlTypes.BLOB;
import static org.hibernate.type.SqlTypes.BOOLEAN;
import static org.hibernate.type.SqlTypes.CHAR;
import static org.hibernate.type.SqlTypes.CLOB;
import static org.hibernate.type.SqlTypes.DATE;
Expand Down Expand Up @@ -434,7 +432,7 @@ protected void initDefaultProperties() {
protected void registerColumnTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
final DdlTypeRegistry ddlTypeRegistry = typeContributions.getTypeConfiguration().getDdlTypeRegistry();

ddlTypeRegistry.addDescriptor( simpleSqlType( BOOLEAN ) );
ddlTypeRegistry.addDescriptor( simpleSqlType( SqlTypes.BOOLEAN ) );

ddlTypeRegistry.addDescriptor( simpleSqlType( TINYINT ) );
ddlTypeRegistry.addDescriptor( simpleSqlType( SMALLINT ) );
Expand Down Expand Up @@ -575,7 +573,7 @@ protected String columnType(int sqlTypeCode) {
return switch (sqlTypeCode) {
case ROWID -> "rowid";

case BOOLEAN -> "boolean";
case SqlTypes.BOOLEAN -> "boolean";

case TINYINT -> "tinyint";
case SMALLINT -> "smallint";
Expand Down Expand Up @@ -1103,8 +1101,8 @@ public int ordinal() {
* functions with the same names.
*/
public void initializeFunctionRegistry(FunctionContributions functionContributions) {
final TypeConfiguration typeConfiguration = functionContributions.getTypeConfiguration();
final BasicTypeRegistry basicTypeRegistry = typeConfiguration.getBasicTypeRegistry();
final var typeConfiguration = functionContributions.getTypeConfiguration();
final var basicTypeRegistry = typeConfiguration.getBasicTypeRegistry();
final BasicType<Date> timestampType = basicTypeRegistry.resolve( StandardBasicTypes.TIMESTAMP );
final BasicType<Date> dateType = basicTypeRegistry.resolve( StandardBasicTypes.DATE );
final BasicType<Date> timeType = basicTypeRegistry.resolve( StandardBasicTypes.TIME );
Expand All @@ -1114,6 +1112,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
final BasicType<LocalTime> localTimeType = basicTypeRegistry.resolve( StandardBasicTypes.LOCAL_TIME );
final BasicType<LocalDate> localDateType = basicTypeRegistry.resolve( StandardBasicTypes.LOCAL_DATE );

final var functionRegistry = functionContributions.getFunctionRegistry();
final var functionFactory = new CommonFunctionFactory( functionContributions );

//standard aggregate functions count(), sum(), max(), min(), avg(),
Expand Down Expand Up @@ -1196,20 +1195,20 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
//only some databases support the ANSI SQL-style position() function, so
//define it here as an alias for locate()

functionContributions.getFunctionRegistry().register( "position",
functionRegistry.register( "position",
new LocatePositionEmulation( typeConfiguration ) );

//very few databases support ANSI-style overlay() function, so emulate
//it here in terms of either insert() or concat()/substring()

functionContributions.getFunctionRegistry().register( "overlay",
functionRegistry.register( "overlay",
new InsertSubstringOverlayEmulation( typeConfiguration, false ) );

//ANSI SQL trim() function is supported on almost all of the databases
//we care about, but on some it must be emulated using ltrim(), rtrim(),
//and replace()

functionContributions.getFunctionRegistry().register( "trim",
functionRegistry.register( "trim",
new TrimFunction( this, typeConfiguration ) );

//ANSI SQL cast() function is supported on the databases we care most
Expand All @@ -1220,7 +1219,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
// - casts to and from Boolean, and
// - casting Double or Float to String.

functionContributions.getFunctionRegistry().register(
functionRegistry.register(
"cast",
new CastFunction(
this,
Expand All @@ -1239,7 +1238,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
//additional non-standard temporal field types, which must be emulated in
//a very dialect-specific way

functionContributions.getFunctionRegistry().register( "extract",
functionRegistry.register( "extract",
new ExtractFunction( this, typeConfiguration ) );

//comparison functions supported on most databases, emulated on others
Expand All @@ -1250,7 +1249,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
//two-argument synonym for coalesce() supported on most but not every
//database, so define it here as an alias for coalesce(arg1,arg2)

functionContributions.getFunctionRegistry().register( "ifnull",
functionRegistry.register( "ifnull",
new CoalesceIfnullEmulation() );

//rpad() and pad() are supported on almost every database, and emulated
Expand All @@ -1261,23 +1260,23 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio

//pad() is a function we've designed to look like ANSI trim()

functionContributions.getFunctionRegistry().register( "pad",
functionRegistry.register( "pad",
new LpadRpadPadEmulation( typeConfiguration ) );

//legacy Hibernate convenience function for casting to string, defined
//here as an alias for cast(arg as String)

functionContributions.getFunctionRegistry().register( "str",
functionRegistry.register( "str",
new CastStrEmulation( typeConfiguration ) );

// Function to convert enum mapped as Ordinal to their ordinal value

functionContributions.getFunctionRegistry().register( "ordinal",
functionRegistry.register( "ordinal",
new OrdinalFunction( typeConfiguration ) );

// Function to convert enum mapped as String to their string value

functionContributions.getFunctionRegistry().register( "string",
functionRegistry.register( "string",
new StringFunction( typeConfiguration ) );

//format() function for datetimes, emulated on many databases using the
Expand All @@ -1290,89 +1289,91 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
//since there is a great variety of different ways to emulate them
//by default, we don't allow plain parameters for the timestamp argument as most database don't support this
functionFactory.timestampaddAndDiff( this, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
functionContributions.getFunctionRegistry().registerAlternateKey( "dateadd", "timestampadd" );
functionContributions.getFunctionRegistry().registerAlternateKey( "datediff", "timestampdiff" );
functionRegistry.registerAlternateKey( "dateadd", "timestampadd" );
functionRegistry.registerAlternateKey( "datediff", "timestampdiff" );

//ANSI SQL (and JPA) current date/time/timestamp functions, supported
//natively on almost every database, delegated back to the Dialect

functionContributions.getFunctionRegistry().register(
functionRegistry.register(
"current_date",
new CurrentFunction(
"current_date",
currentDate(),
dateType
)
);
functionContributions.getFunctionRegistry().register(
functionRegistry.register(
"current_time",
new CurrentFunction(
"current_time",
currentTime(),
timeType
)
);
functionContributions.getFunctionRegistry().register(
functionRegistry.register(
"current_timestamp",
new CurrentFunction(
"current_timestamp",
currentTimestamp(),
timestampType
)
);
functionContributions.getFunctionRegistry().registerAlternateKey( "current date", "current_date" );
functionContributions.getFunctionRegistry().registerAlternateKey( "current time", "current_time" );
functionContributions.getFunctionRegistry().registerAlternateKey( "current timestamp", "current_timestamp" );
functionRegistry.registerAlternateKey( "current date", "current_date" );
functionRegistry.registerAlternateKey( "current time", "current_time" );
functionRegistry.registerAlternateKey( "current timestamp", "current_timestamp" );
//HQL current instant/date/time/datetime functions, delegated back to the Dialect

functionContributions.getFunctionRegistry().register(
functionRegistry.register(
"local_date",
new CurrentFunction(
"local_date",
currentDate(),
localDateType
)
);
functionContributions.getFunctionRegistry().register(
functionRegistry.register(
"local_time",
new CurrentFunction(
"local_time",
currentLocalTime(),
localTimeType
)
);
functionContributions.getFunctionRegistry().register(
functionRegistry.register(
"local_datetime",
new CurrentFunction(
"local_datetime",
currentLocalTimestamp(),
localDateTimeType
)
);
functionContributions.getFunctionRegistry().register(
functionRegistry.register(
"offset_datetime",
new CurrentFunction(
"offset_datetime",
currentTimestampWithTimeZone(),
offsetDateTimeType
)
);
functionContributions.getFunctionRegistry().registerAlternateKey( "local date", "local_date" );
functionContributions.getFunctionRegistry().registerAlternateKey( "local time", "local_time" );
functionContributions.getFunctionRegistry().registerAlternateKey( "local datetime", "local_datetime" );
functionContributions.getFunctionRegistry().registerAlternateKey( "offset datetime", "offset_datetime" );
functionRegistry.registerAlternateKey( "local date", "local_date" );
functionRegistry.registerAlternateKey( "local time", "local_time" );
functionRegistry.registerAlternateKey( "local datetime", "local_datetime" );
functionRegistry.registerAlternateKey( "offset datetime", "offset_datetime" );

functionContributions.getFunctionRegistry().register(
functionRegistry.register(
"instant",
new CurrentFunction(
"instant",
currentTimestampWithTimeZone(),
instantType
)
);
functionContributions.getFunctionRegistry().registerAlternateKey( "current_instant", "instant" ); //deprecated legacy!
functionRegistry.registerAlternateKey( "current_instant", "instant" ); //deprecated legacy!

functionContributions.getFunctionRegistry().register( "sql", new SqlFunction() );
functionRegistry.register( "sql", new SqlFunction() );

functionFactory.regexpLike();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorMariaDBDatabaseImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.VarcharUUIDJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
Expand All @@ -59,11 +58,11 @@

import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
import static org.hibernate.internal.util.JdbcExceptionHelper.extractSqlState;
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.NUMERIC;
import static org.hibernate.type.SqlTypes.GEOMETRY;
import static org.hibernate.type.SqlTypes.OTHER;
import static org.hibernate.type.SqlTypes.UUID;
import static org.hibernate.type.SqlTypes.VARBINARY;
import static org.hibernate.type.StandardBasicTypes.BOOLEAN;

/**
* A {@linkplain Dialect SQL dialect} for MariaDB 10.6 and above.
Expand Down Expand Up @@ -121,15 +120,20 @@ public NationalizationSupport getNationalizationSupport() {
public void initializeFunctionRegistry(FunctionContributions functionContributions) {
super.initializeFunctionRegistry( functionContributions );

final var functionRegistry = functionContributions.getFunctionRegistry();
final var commonFunctionFactory = new CommonFunctionFactory( functionContributions );
final var basicTypeRegistry = functionContributions.getTypeConfiguration().getBasicTypeRegistry();

commonFunctionFactory.windowFunctions();
commonFunctionFactory.hypotheticalOrderedSetAggregates_windowEmulation();
functionContributions.getFunctionRegistry().registerNamed(
commonFunctionFactory.inverseDistributionOrderedSetAggregates_windowEmulation();
commonFunctionFactory.median_medianOver();

commonFunctionFactory.regexpLike_regexp();

functionRegistry.registerNamed(
"json_valid",
functionContributions.getTypeConfiguration()
.getBasicTypeRegistry()
.resolve( StandardBasicTypes.BOOLEAN )
basicTypeRegistry.resolve( BOOLEAN )
);
commonFunctionFactory.jsonValue_mariadb();
commonFunctionFactory.jsonArray_mariadb();
Expand All @@ -139,13 +143,6 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
commonFunctionFactory.jsonArrayAppend_mariadb();
commonFunctionFactory.unnest_emulated();
commonFunctionFactory.jsonTable_mysql();

commonFunctionFactory.inverseDistributionOrderedSetAggregates_windowEmulation();
functionContributions.getFunctionRegistry().patternDescriptorBuilder( "median", "median(?1) over ()" )
.setInvariantType( functionContributions.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE ) )
.setExactArgumentCount( 1 )
.setParameterTypes(NUMERIC)
.register();
}

@Override
Expand Down Expand Up @@ -332,11 +329,6 @@ public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, D
return super.buildIdentifierHelper( builder, metadata );
}

@Override
public String getDual() {
return "dual";
}

public ViolatedConstraintNameExtractor getViolatedConstraintNameExtractor() {
return EXTRACTOR;
}
Expand Down
Loading
Loading