HHH-13778: `@OrderBy` handling using SQL AST
- initial work - Antlr grammar, parse tree visitation and building OrderByFragment (translation) tree - fixed bug in HQL parsing - was building an unnecessary HqlLexer instance
This commit is contained in:
parent
8c671d98d0
commit
8600058784
|
@ -289,9 +289,10 @@ test {
|
|||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Custom Antlr v4 Plugin (to work with Gradle 3)
|
||||
// Custom Antlr v4 Plugin
|
||||
// - the Gradle-supplied Antlr plugin attempts to simultaneously support
|
||||
// multiple versions of Antlr which leads to many difficulties. this custom
|
||||
// plugin provides dedicated and simplified support for Antlr v4
|
||||
|
||||
ext {
|
||||
baseAntlrInputPath = 'src/main/antlr'
|
||||
|
@ -354,6 +355,7 @@ class Antlr4GenerationTask extends DefaultTask {
|
|||
static final String HQL_PCKG = 'org.hibernate.query.hql.internal'
|
||||
static final String IMPORT_SQL_PCKG = 'org.hibernate.tool.hbm2ddl.grammar'
|
||||
static final String GRAPH_PCKG = 'org.hibernate.graph.internal.parse'
|
||||
static final String ORDER_PCKG = 'org.hibernate.grammars.ordering'
|
||||
|
||||
List<GrammarDescriptor> grammarDescriptors = [
|
||||
new GrammarDescriptor( HQL_PCKG, 'HqlLexer' ),
|
||||
|
@ -361,7 +363,9 @@ class Antlr4GenerationTask extends DefaultTask {
|
|||
new GrammarDescriptor( IMPORT_SQL_PCKG, 'SqlStatementLexer' ),
|
||||
new GrammarDescriptor( IMPORT_SQL_PCKG, 'SqlStatementParser' ),
|
||||
new GrammarDescriptor( GRAPH_PCKG, 'GraphLanguageLexer' ),
|
||||
new GrammarDescriptor( GRAPH_PCKG, 'GraphLanguageParser' )
|
||||
new GrammarDescriptor( GRAPH_PCKG, 'GraphLanguageParser' ),
|
||||
new GrammarDescriptor( ORDER_PCKG, 'OrderingLexer' ),
|
||||
new GrammarDescriptor( ORDER_PCKG, 'OrderingParser' )
|
||||
]
|
||||
|
||||
@InputFiles
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
header
|
||||
{
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.sql.ordering.antlr;
|
||||
}
|
||||
/**
|
||||
* Antlr grammar for rendering <tt>ORDER_BY</tt> trees as described by the {@link OrderByFragmentParser}
|
||||
|
||||
* @author Steve Ebersole
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
class GeneratedOrderByFragmentRenderer extends TreeParser;
|
||||
|
||||
options {
|
||||
importVocab=OrderByTemplate;
|
||||
buildAST=false;
|
||||
}
|
||||
|
||||
{
|
||||
// the buffer to which we write the resulting SQL.
|
||||
private StringBuilder buffer = new StringBuilder();
|
||||
|
||||
protected void out(String text) {
|
||||
buffer.append( text );
|
||||
}
|
||||
|
||||
protected void out(AST ast) {
|
||||
buffer.append( ast.getText() );
|
||||
}
|
||||
|
||||
/*package*/ String getRenderedFragment() {
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation note: This is just a stub. OrderByFragmentRenderer contains the effective implementation.
|
||||
*/
|
||||
protected String renderOrderByElement(String expression, String collation, String order, String nulls) {
|
||||
throw new UnsupportedOperationException("Concrete ORDER BY renderer should override this method.");
|
||||
}
|
||||
}
|
||||
|
||||
orderByFragment
|
||||
: #(
|
||||
ORDER_BY sortSpecification ( {out(", ");} sortSpecification)*
|
||||
)
|
||||
;
|
||||
|
||||
sortSpecification { String sortKeySpec = null; String collSpec = null; String ordSpec = null; String nullOrd = null; }
|
||||
: #(
|
||||
SORT_SPEC sortKeySpec=sortKeySpecification (collSpec=collationSpecification)? (ordSpec=orderingSpecification)? (nullOrd=nullOrdering)?
|
||||
{ out( renderOrderByElement( sortKeySpec, collSpec, ordSpec, nullOrd ) ); }
|
||||
)
|
||||
;
|
||||
|
||||
sortKeySpecification returns [String sortKeyExp = null]
|
||||
: #(SORT_KEY s:sortKey) { sortKeyExp = #s.getText(); }
|
||||
;
|
||||
|
||||
sortKey
|
||||
: IDENT
|
||||
;
|
||||
|
||||
collationSpecification returns [String collSpecExp = null]
|
||||
: c:COLLATE { collSpecExp = "collate " + #c.getText(); }
|
||||
;
|
||||
|
||||
orderingSpecification returns [String ordSpecExp = null]
|
||||
: o:ORDER_SPEC { ordSpecExp = #o.getText(); }
|
||||
;
|
||||
|
||||
nullOrdering returns [String nullOrdExp = null]
|
||||
: n:NULL_ORDER { nullOrdExp = #n.getText(); }
|
||||
;
|
|
@ -1,469 +0,0 @@
|
|||
header
|
||||
{
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.sql.ordering.antlr;
|
||||
}
|
||||
/**
|
||||
* Antlr grammar for dealing with <tt>order-by</tt> mapping fragments.
|
||||
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
class GeneratedOrderByFragmentParser extends Parser;
|
||||
|
||||
options
|
||||
{
|
||||
exportVocab=OrderByTemplate;
|
||||
buildAST=true;
|
||||
k=3;
|
||||
}
|
||||
|
||||
tokens
|
||||
{
|
||||
// synthetic tokens
|
||||
ORDER_BY;
|
||||
SORT_SPEC;
|
||||
ORDER_SPEC;
|
||||
NULL_ORDER;
|
||||
SORT_KEY;
|
||||
EXPR_LIST;
|
||||
DOT;
|
||||
IDENT_LIST;
|
||||
COLUMN_REF;
|
||||
|
||||
COLLATE="collate";
|
||||
ASCENDING="asc";
|
||||
DESCENDING="desc";
|
||||
NULLS="nulls";
|
||||
FIRST;
|
||||
LAST;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
/**
|
||||
* Method for logging execution trace information.
|
||||
*
|
||||
* @param msg The trace message.
|
||||
*/
|
||||
@org.hibernate.internal.build.AllowSysOut
|
||||
protected void trace(String msg) {
|
||||
System.out.println( msg );
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a node's text.
|
||||
*
|
||||
* @param ast The node
|
||||
*
|
||||
* @return The text.
|
||||
*/
|
||||
protected final String extractText(AST ast) {
|
||||
// for some reason, within AST creation blocks "[]" I am sometimes unable to refer to the AST.getText() method
|
||||
// using #var (the #var is not interpreted as the rule's output AST).
|
||||
return ast.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the given node as a quote identifier. These need to be quoted in the dialect-specific way.
|
||||
*
|
||||
* @param ident The quoted-identifier node.
|
||||
*
|
||||
* @return The processed node.
|
||||
*
|
||||
* @see org.hibernate.dialect.Dialect#quote
|
||||
*/
|
||||
protected AST quotedIdentifier(AST ident) {
|
||||
return ident;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the given node as a quote string.
|
||||
*
|
||||
* @param ident The quoted string. This is used from within function param recognition, and represents a
|
||||
* SQL-quoted string.
|
||||
*
|
||||
* @return The processed node.
|
||||
*/
|
||||
protected AST quotedString(AST ident) {
|
||||
return ident;
|
||||
}
|
||||
|
||||
/**
|
||||
* A check to see if the text of the given node represents a known function name.
|
||||
*
|
||||
* @param ast The node whose text we want to check.
|
||||
*
|
||||
* @return True if the node's text is a known function name, false otherwise.
|
||||
*
|
||||
* @see org.hibernate.dialect.function.SQLFunctionRegistry
|
||||
*/
|
||||
protected boolean isFunctionName(AST ast) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the given node as a function.
|
||||
*
|
||||
* @param The node representing the function invocation (including parameters as subtree components).
|
||||
*
|
||||
* @return The processed node.
|
||||
*/
|
||||
protected AST resolveFunction(AST ast) {
|
||||
return ast;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the given node as an IDENT. May represent either a column reference or a property reference.
|
||||
*
|
||||
* @param ident The node whose text represents either a column or property reference.
|
||||
*
|
||||
* @return The processed node.
|
||||
*/
|
||||
protected AST resolveIdent(AST ident) {
|
||||
return ident;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow post processing of each <tt>sort specification</tt>
|
||||
*
|
||||
* @param The grammar-built sort specification subtree.
|
||||
*
|
||||
* @return The processed sort specification subtree.
|
||||
*/
|
||||
protected AST postProcessSortSpecification(AST sortSpec) {
|
||||
return sortSpec;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Main recognition rule for this grammar
|
||||
*/
|
||||
orderByFragment { trace("orderByFragment"); }
|
||||
: sortSpecification ( COMMA! sortSpecification )* {
|
||||
#orderByFragment = #( [ORDER_BY, "order-by"], #orderByFragment );
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
* Recognition rule for what ANSI SQL terms the <tt>sort specification</tt>, which is essentially each thing upon which
|
||||
* the results should be sorted.
|
||||
*/
|
||||
sortSpecification { trace("sortSpecification"); }
|
||||
: sortKey (collationSpecification)? (orderingSpecification)? (nullOrdering)? {
|
||||
#sortSpecification = #( [SORT_SPEC, "{sort specification}"], #sortSpecification );
|
||||
#sortSpecification = postProcessSortSpecification( #sortSpecification );
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
* Recognition rule for what ANSI SQL terms the <tt>sort key</tt> which is the expression (column, function, etc) upon
|
||||
* which to base the sorting.
|
||||
*/
|
||||
sortKey! { trace("sortKey"); }
|
||||
: e:expression {
|
||||
#sortKey = #( [SORT_KEY, "sort key"], #e );
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
* Recognition rule what this grammar recognizes as valid <tt>sort key</tt>.
|
||||
*/
|
||||
expression! { trace("expression"); }
|
||||
: HARD_QUOTE qi:IDENT HARD_QUOTE {
|
||||
#expression = quotedIdentifier( #qi );
|
||||
}
|
||||
| ( IDENT (DOT IDENT)* OPEN_PAREN ) => f:functionCall {
|
||||
#expression = #f;
|
||||
}
|
||||
| p:simplePropertyPath {
|
||||
#expression = resolveIdent( #p );
|
||||
}
|
||||
| i:IDENT {
|
||||
if ( isFunctionName( #i ) ) {
|
||||
#expression = resolveFunction( #i );
|
||||
}
|
||||
else {
|
||||
#expression = resolveIdent( #i );
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
* Intended for use as a syntactic predicate to determine whether an IDENT represents a known SQL function name.
|
||||
*/
|
||||
functionCallCheck! { trace("functionCallCheck"); }
|
||||
: IDENT (DOT IDENT)* OPEN_PAREN { true }?
|
||||
;
|
||||
|
||||
/**
|
||||
* Recognition rule for a function call
|
||||
*/
|
||||
functionCall! { trace("functionCall"); }
|
||||
: fn:functionName OPEN_PAREN pl:functionParameterList CLOSE_PAREN {
|
||||
#functionCall = #( [IDENT, extractText( #fn )], #pl );
|
||||
#functionCall = resolveFunction( #functionCall );
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
* A function-name is an IDENT followed by zero or more (DOT IDENT) sequences
|
||||
*/
|
||||
functionName {
|
||||
trace("functionName");
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
}
|
||||
: i:IDENT { buffer.append( i.getText() ); }
|
||||
( DOT i2:IDENT { buffer.append( '.').append( i2.getText() ); } )* {
|
||||
#functionName = #( [IDENT,buffer.toString()] );
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
* Recognition rule used to "wrap" all function parameters into an EXPR_LIST node
|
||||
*/
|
||||
functionParameterList { trace("functionParameterList"); }
|
||||
: functionParameter ( COMMA! functionParameter )* {
|
||||
#functionParameterList = #( [EXPR_LIST, "{param list}"], #functionParameterList );
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
* Recognized function parameters.
|
||||
*/
|
||||
functionParameter { trace("functionParameter"); }
|
||||
: expression
|
||||
| NUM_DOUBLE
|
||||
| NUM_FLOAT
|
||||
| NUM_INT
|
||||
| NUM_LONG
|
||||
| QUOTED_STRING {
|
||||
#functionParameter = quotedString( #functionParameter );
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
* Recognition rule for what ANSI SQL terms the <tt>collation specification</tt> used to allow specifying that sorting for
|
||||
* the given {@link #sortSpecification} be treated within a specific character-set.
|
||||
*/
|
||||
collationSpecification! { trace("collationSpecification"); }
|
||||
: c:COLLATE cn:collationName {
|
||||
#collationSpecification = #( [COLLATE, extractText( #cn )] );
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
* The collation name wrt {@link #collationSpecification}. Namely, the character-set.
|
||||
*/
|
||||
collationName { trace("collationSpecification"); }
|
||||
: IDENT
|
||||
;
|
||||
|
||||
/**
|
||||
* Recognition rule for what ANSI SQL terms the <tt>ordering specification</tt>; <tt>ASCENDING</tt> or
|
||||
* <tt>DESCENDING</tt>.
|
||||
*/
|
||||
orderingSpecification! { trace("orderingSpecification"); }
|
||||
: ( "asc" | "ascending" ) {
|
||||
#orderingSpecification = #( [ORDER_SPEC, "asc"] );
|
||||
}
|
||||
| ( "desc" | "descending") {
|
||||
#orderingSpecification = #( [ORDER_SPEC, "desc"] );
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
* Recognition rule for what SQL-2003 terms the <tt>null ordering</tt>; <tt>NULLS FIRST</tt> or
|
||||
* <tt>NULLS LAST</tt>.
|
||||
*/
|
||||
nullOrdering! { trace("nullOrdering"); }
|
||||
: NULLS n:nullPrecedence {
|
||||
#nullOrdering = #( [NULL_ORDER, extractText( #n )] );
|
||||
}
|
||||
;
|
||||
|
||||
nullPrecedence { trace("nullPrecedence"); }
|
||||
: IDENT {
|
||||
if ( "first".equalsIgnoreCase( #nullPrecedence.getText() ) ) {
|
||||
#nullPrecedence.setType( FIRST );
|
||||
}
|
||||
else if ( "last".equalsIgnoreCase( #nullPrecedence.getText() ) ) {
|
||||
#nullPrecedence.setType( LAST );
|
||||
}
|
||||
else {
|
||||
throw new SemanticException( "Expecting 'first' or 'last', but found '" + #nullPrecedence.getText() + "' as null ordering precedence." );
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
* A simple-property-path is an IDENT followed by one or more (DOT IDENT) sequences
|
||||
*/
|
||||
simplePropertyPath {
|
||||
trace("simplePropertyPath");
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
}
|
||||
: i:IDENT { buffer.append( i.getText() ); }
|
||||
( DOT i2:IDENT { buffer.append( '.').append( i2.getText() ); } )+ {
|
||||
#simplePropertyPath = #( [IDENT,buffer.toString()] );
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
// **** LEXER ******************************************************************
|
||||
|
||||
/**
|
||||
* Lexer for the <tt>order-by</tt> fragment parser
|
||||
|
||||
* @author Steve Ebersole
|
||||
* @author Joshua Davis
|
||||
*/
|
||||
class GeneratedOrderByLexer extends Lexer;
|
||||
|
||||
options {
|
||||
exportVocab=OrderByTemplate;
|
||||
testLiterals = false;
|
||||
k=2;
|
||||
charVocabulary='\u0000'..'\uFFFE'; // Allow any char but \uFFFF (16 bit -1, ANTLR's EOF character)
|
||||
caseSensitive = false;
|
||||
caseSensitiveLiterals = false;
|
||||
}
|
||||
|
||||
// -- Keywords --
|
||||
|
||||
OPEN_PAREN: '(';
|
||||
CLOSE_PAREN: ')';
|
||||
|
||||
COMMA: ',';
|
||||
|
||||
HARD_QUOTE: '`';
|
||||
|
||||
IDENT options { testLiterals=true; }
|
||||
: ID_START_LETTER ( ID_LETTER )*
|
||||
;
|
||||
|
||||
protected
|
||||
ID_START_LETTER
|
||||
: '_'
|
||||
| '$'
|
||||
| 'a'..'z'
|
||||
| '\u0080'..'\ufffe' // HHH-558 : Allow unicode chars in identifiers
|
||||
;
|
||||
|
||||
protected
|
||||
ID_LETTER
|
||||
: ID_START_LETTER
|
||||
| '0'..'9'
|
||||
;
|
||||
|
||||
QUOTED_STRING
|
||||
: '\'' ( (ESCqs)=> ESCqs | ~'\'' )* '\''
|
||||
;
|
||||
|
||||
protected
|
||||
ESCqs
|
||||
:
|
||||
'\'' '\''
|
||||
;
|
||||
|
||||
//--- From the Java example grammar ---
|
||||
// a numeric literal
|
||||
NUM_INT
|
||||
{boolean isDecimal=false; Token t=null;}
|
||||
: '.' {_ttype = DOT;}
|
||||
( ('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
|
||||
{
|
||||
if (t != null && t.getText().toUpperCase().indexOf('F')>=0)
|
||||
{
|
||||
_ttype = NUM_FLOAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ttype = NUM_DOUBLE; // assume double
|
||||
}
|
||||
}
|
||||
)?
|
||||
| ( '0' {isDecimal = true;} // special case for just '0'
|
||||
( ('x')
|
||||
( // hex
|
||||
// the 'e'|'E' and float suffix stuff look
|
||||
// like hex digits, hence the (...)+ doesn't
|
||||
// know when to stop: ambig. ANTLR resolves
|
||||
// it correctly by matching immediately. It
|
||||
// is therefore ok to hush warning.
|
||||
options { warnWhenFollowAmbig=false; }
|
||||
: HEX_DIGIT
|
||||
)+
|
||||
| ('0'..'7')+ // octal
|
||||
)?
|
||||
| ('1'..'9') ('0'..'9')* {isDecimal=true;} // non-zero decimal
|
||||
)
|
||||
( ('l') { _ttype = NUM_LONG; }
|
||||
|
||||
// only check to see if it's a float if looks like decimal so far
|
||||
| {isDecimal}?
|
||||
( '.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})?
|
||||
| EXPONENT (f3:FLOAT_SUFFIX {t=f3;})?
|
||||
| f4:FLOAT_SUFFIX {t=f4;}
|
||||
)
|
||||
{
|
||||
if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0)
|
||||
{
|
||||
_ttype = NUM_FLOAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ttype = NUM_DOUBLE; // assume double
|
||||
}
|
||||
}
|
||||
)?
|
||||
;
|
||||
|
||||
// hexadecimal digit (again, note it's protected!)
|
||||
protected
|
||||
HEX_DIGIT
|
||||
: ('0'..'9'|'a'..'f')
|
||||
;
|
||||
|
||||
// a couple protected methods to assist in matching floating point numbers
|
||||
protected
|
||||
EXPONENT
|
||||
: ('e') ('+'|'-')? ('0'..'9')+
|
||||
;
|
||||
|
||||
protected
|
||||
FLOAT_SUFFIX
|
||||
: 'f'|'d'
|
||||
;
|
||||
|
||||
WS : ( ' '
|
||||
| '\t'
|
||||
| '\r' '\n' { newline(); }
|
||||
| '\n' { newline(); }
|
||||
| '\r' { newline(); }
|
||||
)
|
||||
{$setType(Token.SKIP);} //ignore this token
|
||||
;
|
|
@ -0,0 +1,3 @@
|
|||
# Ignore the `*.tokens` file generated by Antlr when running its grammar generation tool
|
||||
|
||||
*.tokens
|
|
@ -0,0 +1,133 @@
|
|||
lexer grammar OrderingLexer;
|
||||
|
||||
|
||||
@header {
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.grammars.ordering;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Whitespace -> ignore
|
||||
WS : ( ' ' | '\t' | '\f' | EOL ) -> skip;
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// fragments and literals
|
||||
|
||||
fragment
|
||||
EOL : [\r\n]+;
|
||||
|
||||
INTEGER_LITERAL : INTEGER_NUMBER ;
|
||||
|
||||
fragment
|
||||
INTEGER_NUMBER : ('0' | '1'..'9' '0'..'9'*) ;
|
||||
|
||||
LONG_LITERAL : INTEGER_NUMBER ('l'|'L');
|
||||
|
||||
BIG_INTEGER_LITERAL : INTEGER_NUMBER ('bi'|'BI') ;
|
||||
|
||||
HEX_LITERAL : '0' ('x'|'X') HEX_DIGIT+ ('l'|'L')? ;
|
||||
|
||||
fragment
|
||||
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;
|
||||
|
||||
OCTAL_LITERAL : '0' ('0'..'7')+ ('l'|'L')? ;
|
||||
|
||||
FLOAT_LITERAL : FLOATING_POINT_NUMBER ('f'|'F')? ;
|
||||
|
||||
fragment
|
||||
FLOATING_POINT_NUMBER
|
||||
: ('0'..'9')+ '.' ('0'..'9')* EXPONENT?
|
||||
| '.' ('0'..'9')+ EXPONENT?
|
||||
| ('0'..'9')+ EXPONENT
|
||||
| ('0'..'9')+
|
||||
;
|
||||
|
||||
DOUBLE_LITERAL : FLOATING_POINT_NUMBER ('d'|'D') ;
|
||||
|
||||
BIG_DECIMAL_LITERAL : FLOATING_POINT_NUMBER ('bd'|'BD') ;
|
||||
|
||||
fragment
|
||||
EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;
|
||||
|
||||
CHARACTER_LITERAL
|
||||
: '\'' ( ESCAPE_SEQUENCE | ~('\''|'\\') ) '\'' {setText(getText().substring(1, getText().length()-1));}
|
||||
;
|
||||
|
||||
STRING_LITERAL
|
||||
: '"' ( ESCAPE_SEQUENCE | ~('\\'|'"') )* '"' {setText(getText().substring(1, getText().length()-1));}
|
||||
| ('\'' ( ESCAPE_SEQUENCE | ~('\\'|'\'') )* '\'')+ {setText(getText().substring(1, getText().length()-1).replace("''", "'"));}
|
||||
;
|
||||
|
||||
fragment
|
||||
ESCAPE_SEQUENCE
|
||||
: '\\' ('b'|'t'|'n'|'f'|'r'|'\\"'|'\''|'\\')
|
||||
| UNICODE_ESCAPE
|
||||
| OCTAL_ESCAPE
|
||||
;
|
||||
|
||||
fragment
|
||||
OCTAL_ESCAPE
|
||||
: '\\' ('0'..'3') ('0'..'7') ('0'..'7')
|
||||
| '\\' ('0'..'7') ('0'..'7')
|
||||
| '\\' ('0'..'7')
|
||||
;
|
||||
|
||||
fragment
|
||||
UNICODE_ESCAPE
|
||||
: '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
|
||||
;
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// collation
|
||||
COLLATE : [cC] [oO] [lL] [lL] [aA] [tT] [eE];
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NULL precedence
|
||||
|
||||
NULLS : 'NULLS' | 'nulls';
|
||||
FIRST : 'FIRST' | 'first';
|
||||
LAST : 'LAST' | 'last';
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// direction
|
||||
|
||||
ASC : [aA] [sS] [cC] ( [eE] [nN] [dD] [iI] [nN] [gG] )?;
|
||||
DESC : [dD] [eE] [sS] [cC] ( [eE] [nN] [dD] [iI] [nN] [gG] )?;
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Identifiers
|
||||
|
||||
IDENTIFIER
|
||||
: ('a'..'z'|'A'..'Z'|'_'|'$'|'\u0080'..'\ufffe')('a'..'z'|'A'..'Z'|'_'|'$'|'0'..'9'|'\u0080'..'\ufffe')*
|
||||
;
|
||||
|
||||
QUOTED_IDENTIFIER
|
||||
: '`' ( ESCAPE_SEQUENCE | ~('\\'|'`') )* '`'
|
||||
;
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// general tokens
|
||||
|
||||
OPEN_PAREN : '(';
|
||||
CLOSE_PAREN : ')';
|
||||
|
||||
COMMA : ',';
|
||||
DOT : '.';
|
||||
|
||||
PLUS : '+';
|
||||
MINUS : '-';
|
||||
MULTIPLY : '*';
|
||||
DIVIDE : '/';
|
||||
MODULO : '%';
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
parser grammar OrderingParser;
|
||||
|
||||
options {
|
||||
tokenVocab=OrderingLexer;
|
||||
}
|
||||
|
||||
@header {
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.grammars.ordering;
|
||||
|
||||
/**
|
||||
* Grammar for parsing order-by fragments.
|
||||
*
|
||||
* @implNote While we could re-use the HQL lexer/parser for order fragment parsing, both the HQL lexer and parser
|
||||
* are way "heavier" than needed here. So we use a simplified lexer and parser that defione just what is needed
|
||||
* to parse the order fragment
|
||||
*/
|
||||
}
|
||||
|
||||
// todo (6.0) : add hooks for keyword-as-identifier logging like we do for HQL?
|
||||
|
||||
orderByFragment
|
||||
: sortSpecification (COMMA sortSpecification)*
|
||||
;
|
||||
|
||||
sortSpecification
|
||||
: expression collationSpecification? direction? nullsPrecedence?
|
||||
;
|
||||
|
||||
expression
|
||||
: function
|
||||
| identifier
|
||||
| dotIdentifier
|
||||
;
|
||||
|
||||
function
|
||||
: simpleFunction
|
||||
| packagedFunction
|
||||
;
|
||||
|
||||
simpleFunction
|
||||
: identifier functionArguments
|
||||
;
|
||||
|
||||
packagedFunction
|
||||
: dotIdentifier functionArguments
|
||||
;
|
||||
|
||||
functionArguments
|
||||
: OPEN_PAREN expression* CLOSE_PAREN
|
||||
;
|
||||
|
||||
collationSpecification
|
||||
: COLLATE identifier
|
||||
;
|
||||
|
||||
direction
|
||||
: ASC | DESC
|
||||
;
|
||||
|
||||
nullsPrecedence
|
||||
: NULLS (FIRST | LAST)
|
||||
;
|
||||
|
||||
identifier
|
||||
: IDENTIFIER
|
||||
// keyword-as-identifier
|
||||
| FIRST
|
||||
| LAST
|
||||
| ASC
|
||||
| DESC
|
||||
| COLLATE
|
||||
;
|
||||
|
||||
dotIdentifier
|
||||
: IDENTIFIER (DOT IDENTIFIER)+
|
||||
;
|
|
@ -298,14 +298,26 @@ havingClause
|
|||
// ORDER BY clause
|
||||
|
||||
orderByClause
|
||||
// todo (6.0) : null precedence
|
||||
: ORDER BY sortSpecification (COMMA sortSpecification)*
|
||||
;
|
||||
|
||||
/**
|
||||
* Specialized rule for ordered Map and Set `@OrderBy` handling
|
||||
*/
|
||||
orderByFragment
|
||||
: sortSpecification (COMMA sortSpecification)*
|
||||
;
|
||||
|
||||
sortSpecification
|
||||
// todo (6.0) : null precedence
|
||||
// : sortExpression collationSpecification? orderingSpecification? nullsPrecedence?
|
||||
: sortExpression collationSpecification? orderingSpecification?
|
||||
;
|
||||
|
||||
//nullsPrecedence
|
||||
// : NULLS (FIRST | LAST)
|
||||
// ;
|
||||
|
||||
sortExpression
|
||||
: identifier
|
||||
| INTEGER_LITERAL
|
||||
|
|
|
@ -10,5 +10,4 @@
|
|||
*
|
||||
* @deprecated (since 6.0) Use Hibernate's mapping model {@link org.hibernate.metamodel.MappingMetamodel}
|
||||
*/
|
||||
@Deprecated
|
||||
package org.hibernate.metadata;
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.metamodel.mapping;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
|
@ -32,4 +33,7 @@ public interface BasicValuedMapping extends ValueMapping, SqlExpressable {
|
|||
default List<JdbcMapping> getJdbcMappings(TypeConfiguration typeConfiguration) {
|
||||
return Collections.singletonList( getJdbcMapping() );
|
||||
}
|
||||
|
||||
BasicType getBasicType();
|
||||
|
||||
}
|
||||
|
|
|
@ -29,4 +29,9 @@ public interface BasicValuedModelPart extends BasicValuedMapping, ModelPart, Fet
|
|||
* Get the value converter applied to this model part if any
|
||||
*/
|
||||
BasicValueConverter getConverter();
|
||||
|
||||
@Override
|
||||
default MappingType getPartMappingType() {
|
||||
return getBasicType();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,8 +56,6 @@ public interface CollectionPart extends ModelPart, Fetchable {
|
|||
|
||||
Nature getNature();
|
||||
|
||||
MappingType getPartTypeDescriptor();
|
||||
|
||||
@Override
|
||||
default String getPartName() {
|
||||
return getNature().getName();
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.mapping;
|
||||
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -16,4 +18,14 @@ public interface EntityDiscriminatorMapping extends VirtualModelPart, BasicValue
|
|||
default String getPartName() {
|
||||
return ROLE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
default MappingType getPartMappingType() {
|
||||
return getBasicType();
|
||||
}
|
||||
|
||||
@Override
|
||||
default JavaTypeDescriptor getJavaTypeDescriptor() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,6 +64,12 @@ public interface EntityMappingType extends ManagedMappingType, Loadable {
|
|||
return getMappedJavaTypeDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
default MappingType getPartMappingType() {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Inheritance
|
||||
|
||||
|
|
|
@ -24,6 +24,11 @@ public interface ManagedMappingType extends MappingType, FetchableContainer {
|
|||
return getMappedJavaTypeDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
default MappingType getPartMappingType() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of attributes defined on this class and any supers
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface MappingTypedModelPart extends ModelPart {
|
||||
MappingType getMappingType();
|
||||
}
|
|
@ -29,6 +29,8 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ModelPart extends MappingModelExpressable {
|
||||
MappingType getPartMappingType();
|
||||
|
||||
JavaTypeDescriptor getJavaTypeDescriptor();
|
||||
|
||||
String getPartName();
|
||||
|
|
|
@ -27,6 +27,11 @@ public abstract class AbstractAttributeMapping implements AttributeMapping {
|
|||
this.declaringType = declaringType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getPartMappingType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttributeName() {
|
||||
return name;
|
||||
|
|
|
@ -48,6 +48,11 @@ public abstract class AbstractEntityDiscriminatorMapping implements EntityDiscri
|
|||
this.mappingType = mappingType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicType getBasicType() {
|
||||
return mappingType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContainingTableExpression() {
|
||||
return tableExpression;
|
||||
|
|
|
@ -70,7 +70,7 @@ public class BasicValuedCollectionPart implements CollectionPart, BasicValuedMod
|
|||
}
|
||||
|
||||
@Override
|
||||
public BasicType getPartTypeDescriptor() {
|
||||
public MappingType getPartMappingType() {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
|
@ -197,4 +197,9 @@ public class BasicValuedCollectionPart implements CollectionPart, BasicValuedMod
|
|||
public List<JdbcMapping> getJdbcMappings(TypeConfiguration typeConfiguration) {
|
||||
return Collections.singletonList( getJdbcMapping() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicType getBasicType() {
|
||||
return mapper;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,11 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu
|
|||
this.jdbcMapping = jdbcMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicType getBasicType() {
|
||||
return getMappedTypeDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicType getMappedTypeDescriptor() {
|
||||
return (BasicType) super.getMappedTypeDescriptor();
|
||||
|
|
|
@ -73,7 +73,7 @@ public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierD
|
|||
}
|
||||
|
||||
@Override
|
||||
public MappingType getPartTypeDescriptor() {
|
||||
public MappingType getPartMappingType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -188,4 +188,9 @@ public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierD
|
|||
public String toString() {
|
||||
return getClass().getSimpleName() + "(" + collectionDescriptor.getRole() + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicType getBasicType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.hibernate.engine.FetchTiming;
|
|||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
||||
|
@ -84,7 +85,7 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
|
|||
}
|
||||
|
||||
@Override
|
||||
public EmbeddableMappingType getPartTypeDescriptor() {
|
||||
public MappingType getPartMappingType() {
|
||||
return getEmbeddableTypeDescriptor();
|
||||
}
|
||||
|
||||
|
|
|
@ -77,6 +77,11 @@ public class EmbeddedIdentifierMappingImpl
|
|||
this.attrColumnNames = attrColumnNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getPartMappingType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaTypeDescriptor getJavaTypeDescriptor() {
|
||||
return getMappedTypeDescriptor().getMappedJavaTypeDescriptor();
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.mapping.Value;
|
|||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
|
@ -63,7 +64,7 @@ public class EntityCollectionPart implements CollectionPart, EntityAssociationMa
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityMappingType getPartTypeDescriptor() {
|
||||
public MappingType getPartMappingType() {
|
||||
return getEntityMappingType();
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.hibernate.mapping.Table;
|
|||
import org.hibernate.mapping.ToOne;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
import org.hibernate.metamodel.MappingMetamodel;
|
||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
|
@ -63,7 +64,6 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
|||
import org.hibernate.metamodel.mapping.StateArrayContributorMetadata;
|
||||
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
||||
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
||||
import org.hibernate.metamodel.MappingMetamodel;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.collection.SQLLoadableCollection;
|
||||
|
@ -80,12 +80,12 @@ import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
|||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.results.graph.basic.BasicFetch;
|
||||
import org.hibernate.sql.results.graph.basic.BasicResult;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.Fetch;
|
||||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
import org.hibernate.sql.results.graph.basic.BasicFetch;
|
||||
import org.hibernate.sql.results.graph.basic.BasicResult;
|
||||
import org.hibernate.type.AssociationType;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.CompositeType;
|
||||
|
@ -134,9 +134,19 @@ public class MappingModelCreationHelper {
|
|||
return propertyAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getPartMappingType() {
|
||||
return getBasicType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getMappedTypeDescriptor() {
|
||||
return ( (BasicType) entityPersister.getIdentifierType() ).getMappedTypeDescriptor();
|
||||
return getBasicType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicType getBasicType() {
|
||||
return (BasicType) entityPersister.getIdentifierType();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -337,6 +347,13 @@ public class MappingModelCreationHelper {
|
|||
|
||||
return new EntityIdentifierMapping() {
|
||||
|
||||
@Override
|
||||
public MappingType getPartMappingType() {
|
||||
// non-encapsulated means that the id attributes are directly defined on the entity
|
||||
// - alternatively we could have the type here be the IdClass descriptor
|
||||
return entityPersister;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyAccess getPropertyAccess() {
|
||||
return propertyAccess;
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
|
@ -39,6 +40,7 @@ import org.hibernate.sql.results.graph.DomainResult;
|
|||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.Fetch;
|
||||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.ForeignKeyDirection;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
@ -298,6 +300,11 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
return Collections.singletonList( jdbcMapping );
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicType getBasicType() {
|
||||
throw new HibernateException( "Unexpected call to SimpleForeignKeyDescriptor#getBasicType" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJdbcTypes(
|
||||
Consumer<JdbcMapping> action,
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface AliasResolver {
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.grammars.ordering.OrderingLexer;
|
||||
import org.hibernate.grammars.ordering.OrderingParser;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.ordering.ast.ParseTreeVisitor;
|
||||
import org.hibernate.metamodel.mapping.ordering.ast.SortSpecification;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.antlr.v4.runtime.BailErrorStrategy;
|
||||
import org.antlr.v4.runtime.BufferedTokenStream;
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.ConsoleErrorListener;
|
||||
import org.antlr.v4.runtime.DefaultErrorStrategy;
|
||||
import org.antlr.v4.runtime.atn.PredictionMode;
|
||||
import org.antlr.v4.runtime.misc.ParseCancellationException;
|
||||
|
||||
/**
|
||||
* Responsible for performing the translation of the order-by fragment associated
|
||||
* with an order set or map.
|
||||
*
|
||||
* @see javax.persistence.OrderBy
|
||||
* @see org.hibernate.annotations.OrderBy
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class OrderByFragmentTranslator {
|
||||
private static final Logger LOG = Logger.getLogger( OrderByFragmentTranslator.class.getName() );
|
||||
|
||||
/**
|
||||
* Perform the translation of the user-supplied fragment, returning the translation.
|
||||
*
|
||||
* @apiNote The important distinction to this split between (1) translating and (2) resolving aliases is that
|
||||
* both happen at different times. This is performed at boot-time while building the CollectionPersister
|
||||
* happens at runtime while loading the described collection
|
||||
*
|
||||
* @return The translation.
|
||||
*/
|
||||
public static OrderByFragment translate(
|
||||
String fragment,
|
||||
PluralAttributeMapping pluralAttributeMapping,
|
||||
TranslationContext context) {
|
||||
LOG.tracef( "Beginning parsing of order-by fragment [%s] : %s", pluralAttributeMapping.getCollectionDescriptor().getRole(), fragment );
|
||||
|
||||
final OrderingParser.OrderByFragmentContext parseTree = buildParseTree( context, fragment );
|
||||
|
||||
final ParseTreeVisitor visitor = new ParseTreeVisitor( pluralAttributeMapping, context );
|
||||
|
||||
final List<SortSpecification> interpretation = visitor.visitOrderByFragment( parseTree );
|
||||
|
||||
throw new NotYetImplementedFor6Exception( OrderByFragmentTranslator.class );
|
||||
}
|
||||
|
||||
|
||||
private static OrderingParser.OrderByFragmentContext buildParseTree(TranslationContext context, String fragment) {
|
||||
final OrderingLexer lexer = new OrderingLexer( CharStreams.fromString( fragment ) );
|
||||
|
||||
final OrderingParser parser = new OrderingParser( new BufferedTokenStream( lexer ) );
|
||||
|
||||
// try to use SLL(k)-based parsing first - its faster
|
||||
parser.getInterpreter().setPredictionMode( PredictionMode.SLL );
|
||||
parser.removeErrorListeners();
|
||||
parser.setErrorHandler( new BailErrorStrategy() );
|
||||
|
||||
try {
|
||||
return parser.orderByFragment();
|
||||
}
|
||||
catch ( ParseCancellationException e) {
|
||||
// reset the input token stream and parser state
|
||||
lexer.reset();
|
||||
parser.reset();
|
||||
|
||||
// fall back to LL(k)-based parsing
|
||||
parser.getInterpreter().setPredictionMode( PredictionMode.LL );
|
||||
parser.addErrorListener( ConsoleErrorListener.INSTANCE );
|
||||
parser.setErrorHandler( new DefaultErrorStrategy() );
|
||||
|
||||
return parser.orderByFragment();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the translation result
|
||||
*/
|
||||
public interface OrderByFragment {
|
||||
/**
|
||||
* Inject table aliases into the translated fragment to properly qualify column references, using
|
||||
* the given 'aliasResolver' to determine the the proper table alias to use for each column reference.
|
||||
*
|
||||
* @param aliasResolver The strategy to resolver the proper table alias to use per column
|
||||
*
|
||||
* @return The fully translated and replaced fragment.
|
||||
*/
|
||||
String injectAliases(AliasResolver aliasResolver);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering;
|
||||
|
||||
/**
|
||||
* Access to information needed while translating a collection's order-by fragment
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface TranslationContext {
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering.ast;
|
||||
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.ordering.TranslationContext;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CollectionSubPath implements DomainPath {
|
||||
private final PluralAttributeMapping pluralAttribute;
|
||||
private final ModelPart referenceModelPart;
|
||||
|
||||
public CollectionSubPath(
|
||||
PluralAttributeMapping pluralAttribute,
|
||||
ModelPart referenceModelPart) {
|
||||
this.pluralAttribute = pluralAttribute;
|
||||
this.referenceModelPart = referenceModelPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluralAttributeMapping getPluralAttribute() {
|
||||
return pluralAttribute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainPath getLhs() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart getReferenceModelPart() {
|
||||
return referenceModelPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SequencePart resolvePathPart(
|
||||
String name,
|
||||
boolean isTerminal,
|
||||
TranslationContext translationContext) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering.ast;
|
||||
|
||||
import org.hibernate.metamodel.mapping.ordering.TranslationContext;
|
||||
|
||||
/**
|
||||
* Represents a column-reference used in an order-by fragment
|
||||
*
|
||||
* @apiNote This is Hibernate-specific feature. For {@link javax.persistence.OrderBy} (JPA)
|
||||
* all path references are expected to be domain paths (attributes).
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ColumnReference implements SortExpression, SequencePart {
|
||||
private final String columnExpression;
|
||||
|
||||
public ColumnReference(String columnExpression) {
|
||||
this.columnExpression = columnExpression;
|
||||
}
|
||||
|
||||
public String getColumnExpression() {
|
||||
return columnExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SequencePart resolvePathPart(
|
||||
String name,
|
||||
boolean isTerminal,
|
||||
TranslationContext translationContext) {
|
||||
throw new UnsupportedOperationException( "ColumnReference cannot be de-referenced" );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering.ast;
|
||||
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
|
||||
/**
|
||||
* Represents a domain-path (model part path) used in an order-by fragment
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface DomainPath extends SortExpression, SequencePart {
|
||||
DomainPath getLhs();
|
||||
|
||||
ModelPart getReferenceModelPart();
|
||||
|
||||
default PluralAttributeMapping getPluralAttribute() {
|
||||
return getLhs().getPluralAttribute();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a function used in an order-by fragment
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class FunctionExpression {
|
||||
private final String name;
|
||||
private final List<SortExpression> arguments;
|
||||
|
||||
public FunctionExpression(String name, int numberOfArguments) {
|
||||
this.name = name;
|
||||
this.arguments = numberOfArguments == 0
|
||||
? Collections.emptyList()
|
||||
: new ArrayList<>( numberOfArguments );
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<SortExpression> getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
public void addArgument(SortExpression argument) {
|
||||
arguments.add( argument );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering.ast;
|
||||
|
||||
/**
|
||||
* Common contract for all nodes in the order-by fragment AST
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface Node {
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.SortOrder;
|
||||
import org.hibernate.grammars.ordering.OrderingParser;
|
||||
import org.hibernate.grammars.ordering.OrderingParserBaseVisitor;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.ordering.TranslationContext;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ParseTreeVisitor extends OrderingParserBaseVisitor {
|
||||
private static final Logger log = Logger.getLogger( ParseTreeVisitor.class );
|
||||
|
||||
private final PathConsumer pathConsumer;
|
||||
private final TranslationContext translationContext;
|
||||
|
||||
private List<SortSpecification> specifications;
|
||||
|
||||
public ParseTreeVisitor(
|
||||
PluralAttributeMapping pluralAttributeMapping,
|
||||
TranslationContext translationContext) {
|
||||
this.pathConsumer = new PathConsumer( pluralAttributeMapping, translationContext );
|
||||
this.translationContext = translationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SortSpecification> visitOrderByFragment(OrderingParser.OrderByFragmentContext parsedFragment) {
|
||||
final List<OrderingParser.SortSpecificationContext> parsedSortSpecifications = parsedFragment.sortSpecification();
|
||||
Objects.requireNonNull( parsedSortSpecifications );
|
||||
|
||||
this.specifications = new ArrayList<>( parsedSortSpecifications.size() );
|
||||
|
||||
for ( OrderingParser.SortSpecificationContext parsedSortSpecification : parsedSortSpecifications ) {
|
||||
visitSortSpecification( parsedSortSpecification );
|
||||
}
|
||||
|
||||
Objects.requireNonNull( specifications );
|
||||
return specifications;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortSpecification visitSortSpecification(OrderingParser.SortSpecificationContext parsedSpec) {
|
||||
assert parsedSpec != null;
|
||||
assert parsedSpec.expression() != null;
|
||||
|
||||
final SortSpecification result = new SortSpecification( visitExpression( parsedSpec.expression() ) );
|
||||
|
||||
if ( parsedSpec.collationSpecification() != null ) {
|
||||
result.setCollation( parsedSpec.collationSpecification().identifier().getText() );
|
||||
}
|
||||
|
||||
if ( parsedSpec.direction() != null ) {
|
||||
if ( parsedSpec.direction().ASC() != null ) {
|
||||
result.setSortOrder( SortOrder.ASCENDING );
|
||||
}
|
||||
}
|
||||
|
||||
// todo (6.0) : null-precedence (see grammar notes)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortExpression visitExpression(OrderingParser.ExpressionContext ctx) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitCollationSpecification(OrderingParser.CollationSpecificationContext ctx) {
|
||||
throw new IllegalStateException( "Unexpected call to #visitCollationSpecification" );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering.ast;
|
||||
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.ordering.TranslationContext;
|
||||
import org.hibernate.query.hql.internal.BasicDotIdentifierConsumer;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* Represents the translation of an individual part of a path in `@OrderBy` translation
|
||||
*
|
||||
* Similar in purpose to {@link org.hibernate.query.hql.spi.DotIdentifierConsumer}, but for `@OrderBy` translation
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class PathConsumer {
|
||||
private static final Logger log = Logger.getLogger( BasicDotIdentifierConsumer.class );
|
||||
|
||||
private final TranslationContext translationContext;
|
||||
|
||||
private final SequencePart rootSequencePart;
|
||||
|
||||
private String pathSoFar;
|
||||
private SequencePart currentPart;
|
||||
|
||||
public PathConsumer(
|
||||
PluralAttributeMapping pluralAttributeMapping, TranslationContext translationContext) {
|
||||
this.translationContext = translationContext;
|
||||
|
||||
this.rootSequencePart = new RootSequencePart( pluralAttributeMapping );
|
||||
}
|
||||
|
||||
public SequencePart getConsumedPart() {
|
||||
return currentPart;
|
||||
}
|
||||
|
||||
public void consumeIdentifier(String identifier, boolean isBase, boolean isTerminal) {
|
||||
if ( isBase ) {
|
||||
// each time we start a new sequence we need to reset our state
|
||||
reset();
|
||||
}
|
||||
|
||||
if ( pathSoFar == null ) {
|
||||
pathSoFar = identifier;
|
||||
}
|
||||
else {
|
||||
pathSoFar += ( '.' + identifier );
|
||||
}
|
||||
|
||||
log.tracef(
|
||||
"BasicDotIdentifierHandler#consumeIdentifier( %s, %s, %s ) - %s",
|
||||
identifier,
|
||||
isBase,
|
||||
isTerminal,
|
||||
pathSoFar
|
||||
);
|
||||
|
||||
currentPart = currentPart.resolvePathPart( identifier, isTerminal, translationContext );
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
pathSoFar = null;
|
||||
currentPart = rootSequencePart;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering.ast;
|
||||
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.ordering.TranslationContext;
|
||||
|
||||
/**
|
||||
* PathPart implementation used to translate the root of a path
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class RootSequencePart implements SequencePart {
|
||||
private final PluralAttributeMapping pluralAttributeMapping;
|
||||
|
||||
public RootSequencePart(PluralAttributeMapping pluralAttributeMapping) {
|
||||
this.pluralAttributeMapping = pluralAttributeMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SequencePart resolvePathPart(
|
||||
String name,
|
||||
boolean isTerminal,
|
||||
TranslationContext translationContext) {
|
||||
// could be a column-reference (isTerminal would have to be true) or a domain-path
|
||||
|
||||
final ModelPart subPart = pluralAttributeMapping.findSubPart( name, null );
|
||||
|
||||
if ( subPart != null ) {
|
||||
return new CollectionSubPath( pluralAttributeMapping, subPart );
|
||||
}
|
||||
|
||||
if ( isTerminal ) {
|
||||
// assume a column-reference
|
||||
return new ColumnReference( name );
|
||||
}
|
||||
|
||||
throw new UnexpectedTokenException(
|
||||
"Could not resolve order-by token : " +
|
||||
pluralAttributeMapping.getCollectionDescriptor().getRole() + " -> " + name
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering.ast;
|
||||
|
||||
import org.hibernate.metamodel.mapping.ordering.TranslationContext;
|
||||
|
||||
/**
|
||||
* Represents an individual identifier in a dot-identifier sequence
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SequencePart {
|
||||
SequencePart resolvePathPart(
|
||||
String name,
|
||||
boolean isTerminal,
|
||||
TranslationContext translationContext);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering.ast;
|
||||
|
||||
/**
|
||||
* Contract for anything that can be a sort expression
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SortExpression extends Node {
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering.ast;
|
||||
|
||||
import org.hibernate.NullPrecedence;
|
||||
import org.hibernate.SortOrder;
|
||||
|
||||
/**
|
||||
* An individual sort specification in an order-by fragment
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SortSpecification implements Node {
|
||||
private final SortExpression sortExpression;
|
||||
|
||||
private String collation;
|
||||
private SortOrder sortOrder;
|
||||
private NullPrecedence nullPrecedence = NullPrecedence.NONE;
|
||||
|
||||
public SortSpecification(SortExpression sortExpression) {
|
||||
this.sortExpression = sortExpression;
|
||||
}
|
||||
|
||||
public SortExpression getSortExpression() {
|
||||
return sortExpression;
|
||||
}
|
||||
|
||||
public String getCollation() {
|
||||
return collation;
|
||||
}
|
||||
|
||||
public void setCollation(String collation) {
|
||||
this.collation = collation;
|
||||
}
|
||||
|
||||
public SortOrder getSortOrder() {
|
||||
return sortOrder;
|
||||
}
|
||||
|
||||
public void setSortOrder(SortOrder sortOrder) {
|
||||
this.sortOrder = sortOrder;
|
||||
}
|
||||
|
||||
public NullPrecedence getNullPrecedence() {
|
||||
return nullPrecedence;
|
||||
}
|
||||
|
||||
public void setNullPrecedence(NullPrecedence nullPrecedence) {
|
||||
this.nullPrecedence = nullPrecedence;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering.ast;
|
||||
|
||||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingTypedModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.ordering.TranslationContext;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SubDomainPath implements DomainPath {
|
||||
private final DomainPath lhs;
|
||||
private final ModelPart referencedModelPart;
|
||||
|
||||
public SubDomainPath(DomainPath lhs, ModelPart referencedModelPart) {
|
||||
this.lhs = lhs;
|
||||
this.referencedModelPart = referencedModelPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainPath getLhs() {
|
||||
return lhs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart getReferenceModelPart() {
|
||||
return referencedModelPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SequencePart resolvePathPart(
|
||||
String name,
|
||||
boolean isTerminal,
|
||||
TranslationContext translationContext) {
|
||||
if ( referencedModelPart.getPartMappingType() instanceof ManagedMappingType ) {
|
||||
final ManagedMappingType partMappingType = (ManagedMappingType) referencedModelPart.getPartMappingType();
|
||||
final ModelPart subPart = partMappingType.findSubPart( name, null );
|
||||
if ( subPart == null ) {
|
||||
throw new UnexpectedTokenException(
|
||||
"Could not resolve path token : " +
|
||||
referencedModelPart + " -> " + name
|
||||
);
|
||||
}
|
||||
|
||||
return new SubDomainPath( this, subPart );
|
||||
}
|
||||
|
||||
throw new UnexpectedTokenException(
|
||||
"Domain path of type `" + referencedModelPart.getPartMappingType() +
|
||||
"` -> `" + name + "`"
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering.ast;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class UnexpectedTokenException extends HibernateException {
|
||||
public UnexpectedTokenException(String message) {
|
||||
super( message );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support for set and map ordering
|
||||
*
|
||||
* @see javax.persistence.OrderBy
|
||||
* @see org.hibernate.annotations.OrderBy
|
||||
*/
|
||||
package org.hibernate.metamodel.mapping.ordering;
|
|
@ -28,11 +28,12 @@ public class HqlParseTreeBuilder {
|
|||
*/
|
||||
public static final HqlParseTreeBuilder INSTANCE = new HqlParseTreeBuilder();
|
||||
|
||||
public HqlParser generateHqlParser(String hql) {
|
||||
// Build the lexer
|
||||
HqlLexer hqlLexer = new HqlLexer( CharStreams.fromString( hql ) );
|
||||
public HqlLexer buildHqlLexer(String hql) {
|
||||
return new HqlLexer( CharStreams.fromString( hql ) );
|
||||
}
|
||||
|
||||
// Build the parser...
|
||||
public HqlParser buildHqlParser(String hql, HqlLexer hqlLexer) {
|
||||
// Build the parser
|
||||
return new HqlParser( new CommonTokenStream( hqlLexer ) ) {
|
||||
@Override
|
||||
protected void logUseOfReservedWordAsIdentifier(Token token) {
|
||||
|
@ -42,4 +43,9 @@ public class HqlParseTreeBuilder {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
public HqlParser buildHqlParser(String hql) {
|
||||
// Build the lexer
|
||||
return buildHqlParser( hql, buildHqlLexer( hql ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ import org.hibernate.query.hql.spi.SqmCreationOptions;
|
|||
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||
|
||||
import org.antlr.v4.runtime.BailErrorStrategy;
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.ConsoleErrorListener;
|
||||
import org.antlr.v4.runtime.DefaultErrorStrategy;
|
||||
import org.antlr.v4.runtime.atn.PredictionMode;
|
||||
|
@ -64,10 +63,10 @@ public class StandardHqlTranslator implements HqlTranslator {
|
|||
|
||||
private HqlParser.StatementContext parseHql(String hql) {
|
||||
// Build the lexer
|
||||
final HqlLexer hqlLexer = new HqlLexer( CharStreams.fromString( hql ) );
|
||||
final HqlLexer hqlLexer = HqlParseTreeBuilder.INSTANCE.buildHqlLexer( hql );
|
||||
|
||||
// first, ask Antlr to build the parse tree
|
||||
final HqlParser hqlParser = HqlParseTreeBuilder.INSTANCE.generateHqlParser( hql );
|
||||
// Build the parse tree
|
||||
final HqlParser hqlParser = HqlParseTreeBuilder.INSTANCE.buildHqlParser( hql, hqlLexer );
|
||||
|
||||
// try to use SLL(k)-based parsing first - its faster
|
||||
hqlParser.getInterpreter().setPredictionMode( PredictionMode.SLL );
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.hibernate.LockMode;
|
|||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||
import org.hibernate.sql.results.graph.BiDirectionalFetch;
|
||||
|
@ -97,6 +98,11 @@ public class BiDirectionalFetchImpl implements BiDirectionalFetch, Fetchable {
|
|||
return fetchable.getFetchableName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getPartMappingType() {
|
||||
return fetchable.getPartMappingType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaTypeDescriptor getJavaTypeDescriptor() {
|
||||
return fetchable.getJavaTypeDescriptor();
|
||||
|
|
|
@ -32,6 +32,11 @@ public interface BasicType<T> extends Type, BasicDomainType<T>, MappingType, Bas
|
|||
*/
|
||||
String[] getRegistrationKeys();
|
||||
|
||||
@Override
|
||||
default BasicType getBasicType() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
default MappingType getMappedTypeDescriptor() {
|
||||
return this;
|
||||
|
|
Loading…
Reference in New Issue