Author: brmeyer
Date: 2012-08-30 12:55:39 -0400 (Thu, 30 Aug 2012)
New Revision: 21065
Added:
core/patches/JBPAPP-6940/grammar/order-by-render.g
core/patches/JBPAPP-6940/grammar/order-by.g
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/CollationSpecification.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/ColumnMapper.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/ColumnReference.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/Factory.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/FormulaReference.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/Node.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/NodeSupport.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByAliasResolver.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByFragment.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByFragmentParser.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByFragmentRenderer.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByFragmentTranslator.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByTranslation.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderingSpecification.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/SortKey.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/SortSpecification.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/SqlValueReference.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/TranslationContext.java
Modified:
annotations/patches/JBPAPP-6940/
annotations/patches/JBPAPP-6940/jdbc/
annotations/patches/JBPAPP-6940/src/java/org/hibernate/cfg/annotations/CollectionBinder.java
annotations/patches/JBPAPP-6940/src/test/org/hibernate/test/annotations/manytomany/ManyToManyTest.java
annotations/patches/JBPAPP-6940/src/test/org/hibernate/test/annotations/onetomany/OneToManyTest.java
core/patches/JBPAPP-6940/
core/patches/JBPAPP-6940/build.xml
core/patches/JBPAPP-6940/src/org/hibernate/hql/ast/util/ASTPrinter.java
core/patches/JBPAPP-6940/src/org/hibernate/persister/collection/AbstractCollectionPersister.java
core/patches/JBPAPP-6940/src/org/hibernate/persister/entity/AbstractEntityPersister.java
core/patches/JBPAPP-6940/src/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java
core/patches/JBPAPP-6940/src/org/hibernate/persister/entity/Loadable.java
core/patches/JBPAPP-6940/src/org/hibernate/persister/entity/Queryable.java
core/patches/JBPAPP-6940/src/org/hibernate/sql/Template.java
core/patches/JBPAPP-6940/src/org/hibernate/util/StringHelper.java
Log:
JBPAPP-6940 ManyToManyTest.testOrderByContractor fails on DB2 and Sybase
Property changes on: annotations/patches/JBPAPP-6940
___________________________________________________________________
Added: svn:ignore
+ .settings
build
.classpath
.project
Property changes on: annotations/patches/JBPAPP-6940/jdbc
___________________________________________________________________
Added: svn:ignore
+ db2jcc_license_cu.jar
db2jcc.jar
sqlj.zip
Modified:
annotations/patches/JBPAPP-6940/src/java/org/hibernate/cfg/annotations/CollectionBinder.java
===================================================================
---
annotations/patches/JBPAPP-6940/src/java/org/hibernate/cfg/annotations/CollectionBinder.java 2012-08-30
16:52:35 UTC (rev 21064)
+++
annotations/patches/JBPAPP-6940/src/java/org/hibernate/cfg/annotations/CollectionBinder.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -1,12 +1,10 @@
package org.hibernate.cfg.annotations;
-import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
-import java.util.StringTokenizer;
+
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Embeddable;
@@ -78,9 +76,7 @@
import org.hibernate.mapping.ManyToOne;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
-import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.SimpleValue;
-import org.hibernate.mapping.SingleTableSubclass;
import org.hibernate.mapping.Table;
import org.hibernate.util.StringHelper;
@@ -817,186 +813,33 @@
}
}
- private static String buildOrderByClauseFromHql(String hqlOrderBy, PersistentClass
associatedClass, String role) {
- String orderByString = null;
- if ( hqlOrderBy != null ) {
- List<String> properties = new ArrayList<String>();
- List<String> ordering = new ArrayList<String>();
- StringBuilder orderByBuffer = new StringBuilder();
- if ( hqlOrderBy.length() == 0 ) {
+ private static String buildOrderByClauseFromHql(String orderByFragment, PersistentClass
associatedClass, String role) {
+ if ( orderByFragment != null ) {
+ if ( orderByFragment.length() == 0 ) {
//order by id
- Iterator it = associatedClass.getIdentifier().getColumnIterator();
- while ( it.hasNext() ) {
- Selectable col = (Selectable) it.next();
- orderByBuffer.append( col.getText() ).append( " asc" ).append( ",
" );
- }
+ return "id asc";
}
- else {
- StringTokenizer st = new StringTokenizer( hqlOrderBy, " ,", false );
- String currentOrdering = null;
- //FIXME make this code decent
- while ( st.hasMoreTokens() ) {
- String token = st.nextToken();
- if ( isNonPropertyToken( token ) ) {
- if ( currentOrdering != null ) {
- throw new AnnotationException(
- "Error while parsing HQL orderBy clause: " + hqlOrderBy
- + " (" + role + ")"
- );
- }
- currentOrdering = token;
- }
- else {
- //Add ordering of the previous
- if ( currentOrdering == null ) {
- //default ordering
- ordering.add( "asc" );
- }
- else {
- ordering.add( currentOrdering );
- currentOrdering = null;
- }
- properties.add( token );
- }
- }
- ordering.remove( 0 ); //first one is the algorithm starter
- // add last one ordering
- if ( currentOrdering == null ) {
- //default ordering
- ordering.add( "asc" );
- }
- else {
- ordering.add( currentOrdering );
- currentOrdering = null;
- }
- int index = 0;
-
- for (String property : properties) {
- Property p = BinderHelper.findPropertyByName( associatedClass, property );
- if ( p == null ) {
- throw new AnnotationException(
- "property from @OrderBy clause not found: "
- + associatedClass.getEntityName() + "." + property
- );
- }
- PersistentClass pc = p.getPersistentClass();
- String table;
- if ( pc == null ) {
- //we are touching a @IdClass property, the pc is not set
- //this means pc == associatedClass
- //TODO check whether @ManyToOne @JoinTable in @IdClass used for @OrderBy works:
doh!
- table = "";
- }
- else if (pc == associatedClass
- || (associatedClass instanceof SingleTableSubclass && pc
- .getMappedClass().isAssignableFrom(
- associatedClass.getMappedClass()))) {
- table = "";
- } else {
- table = pc.getTable().getQuotedName() + ".";
- }
- Iterator propertyColumns = p.getColumnIterator();
- while ( propertyColumns.hasNext() ) {
- Selectable column = (Selectable) propertyColumns.next();
- orderByBuffer.append( table )
- .append( column.getText() )
- .append( " " )
- .append( ordering.get( index ) )
- .append( ", " );
- }
- index++;
- }
+ else if ( "desc".equals( orderByFragment ) ) {
+ return "id desc";
}
- orderByString = orderByBuffer.substring( 0, orderByBuffer.length() - 2 );
}
- return orderByString;
+ return orderByFragment;
}
- private static String buildOrderByClauseFromHql(String hqlOrderBy, Component component,
String role) {
- String orderByString = null;
- if ( hqlOrderBy != null ) {
- List<String> properties = new ArrayList<String>();
- List<String> ordering = new ArrayList<String>();
- StringBuilder orderByBuffer = new StringBuilder();
- if ( hqlOrderBy.length() == 0 ) {
- //TODO : Check that. Maybe order by key for maps
+ private static String adjustUserSuppliedValueCollectionOrderingFragment(String
orderByFragment) {
+ if ( orderByFragment != null ) {
+ // NOTE: "$element$" is a specially recognized collection property
recognized by the collection persister
+ if ( orderByFragment.length() == 0 ) {
+ //order by element
+ return "$element$ asc";
}
- else {
- StringTokenizer st = new StringTokenizer( hqlOrderBy, " ,", false );
- String currentOrdering = null;
- //FIXME make this code decent
- while ( st.hasMoreTokens() ) {
- String token = st.nextToken();
- if ( isNonPropertyToken( token ) ) {
- if ( currentOrdering != null ) {
- throw new AnnotationException(
- "Error while parsing HQL orderBy clause: " + hqlOrderBy
- + " (" + role + ")"
- );
- }
- currentOrdering = token;
- }
- else {
- //Add ordering of the previous
- if ( currentOrdering == null ) {
- //default ordering
- ordering.add( "asc" );
- }
- else {
- ordering.add( currentOrdering );
- currentOrdering = null;
- }
- properties.add( token );
- }
- }
- ordering.remove( 0 ); //first one is the algorithm starter
- // add last one ordering
- if ( currentOrdering == null ) {
- //default ordering
- ordering.add( "asc" );
- }
- else {
- ordering.add( currentOrdering );
- currentOrdering = null;
- }
- int index = 0;
-
- for (String property : properties) {
- Property p = component.getProperty( property );
- if ( p == null ) {
- throw new AnnotationException(
- "property from @OrderBy clause not found: "
- + role + "." + property
- );
- }
-
- Iterator propertyColumns = p.getColumnIterator();
- while ( propertyColumns.hasNext() ) {
- Selectable column = (Selectable) propertyColumns.next();
- orderByBuffer.append( column.getText() )
- .append( " " )
- .append( ordering.get( index ) )
- .append( ", " );
- }
- index++;
- }
-
- if ( orderByBuffer.length() >= 2 ) {
- orderByString = orderByBuffer.substring( 0, orderByBuffer.length() - 2 );
- }
+ else if ( "desc".equals( orderByFragment ) ) {
+ return "$element$ desc";
}
}
- return orderByString;
+ return orderByFragment;
}
- private static boolean isNonPropertyToken(String token) {
- if ( " ".equals( token ) ) return true;
- if ( ",".equals( token ) ) return true;
- if ( token.equalsIgnoreCase( "desc" ) ) return true;
- if ( token.equalsIgnoreCase( "asc" ) ) return true;
- return false;
- }
-
private static SimpleValue buildCollectionKey(
Collection collValue, Ejb3JoinColumn[] joinColumns, boolean cascadeDeleteEnabled,
XProperty property, ExtendedMappings mappings
@@ -1265,7 +1108,7 @@
if ( StringHelper.isNotEmpty( hqlOrderBy ) ) {
String path = collValue.getOwnerEntityName() + "." +
joinColumns[0].getPropertyName();
- String orderBy = buildOrderByClauseFromHql( hqlOrderBy, component, path );
+ String orderBy = adjustUserSuppliedValueCollectionOrderingFragment( hqlOrderBy );
if ( orderBy != null ) {
collValue.setOrderBy( orderBy );
}
@@ -1296,6 +1139,10 @@
elementBinder.setColumns( elementColumns );
elementBinder.setType( property, elementClass );
collValue.setElement( elementBinder.make() );
+ String orderBy = adjustUserSuppliedValueCollectionOrderingFragment( hqlOrderBy );
+ if ( orderBy != null ) {
+ collValue.setOrderBy( orderBy );
+ }
}
}
Modified:
annotations/patches/JBPAPP-6940/src/test/org/hibernate/test/annotations/manytomany/ManyToManyTest.java
===================================================================
---
annotations/patches/JBPAPP-6940/src/test/org/hibernate/test/annotations/manytomany/ManyToManyTest.java 2012-08-30
16:52:35 UTC (rev 21064)
+++
annotations/patches/JBPAPP-6940/src/test/org/hibernate/test/annotations/manytomany/ManyToManyTest.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -14,10 +14,6 @@
import org.hibernate.JDBCException;
import org.hibernate.Session;
import org.hibernate.Transaction;
-import org.hibernate.dialect.MySQLDialect;
-import org.hibernate.dialect.Oracle8iDialect;
-import org.hibernate.dialect.PostgreSQLDialect;
-import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.test.annotations.TestCase;
/**
@@ -258,38 +254,9 @@
s.close();
}
- /**
- * ANN-625
- *
- * @throws Exception in case the test fails.
- *
- * This test only works against databases which allow a mixed usage of
- * table names and table aliases. The generated SQL for this test is:
- *
- * select
- * contractor0_.EMPLOYER_ID as EMPLOYER1_1_,
- * contractor0_.CONTRACTOR_ID as CONTRACTOR2_1_,
- * contractor1_.id as id2_0_,
- * contractor1_.fld_name as fld3_2_0_,
- * contractor1_.hourlyRate as hourlyRate2_0_
- * from
- * EMPLOYER_CONTRACTOR contractor0_
- * left outer join
- * Employee contractor1_
- * on contractor0_.CONTRACTOR_ID=contractor1_.id
- * where
- * contractor0_.EMPLOYER_ID=?
- * order by
- * Employee.fld_name desc
- *
- *
- */
-// HHH-3577 JBPAPP-1123
+
+ // HHH-4394
public void testOrderByContractor() throws Exception {
- if(getDialect() instanceof MySQLDialect || getDialect() instanceof PostgreSQLDialect ||
getDialect() instanceof SQLServerDialect|| getDialect() instanceof Oracle8iDialect){
- log.warn("skip test testOrderByContractor due to JBPAPP-1123");
- return;
- }
Session s;
Transaction tx;
s = openSession();
Modified:
annotations/patches/JBPAPP-6940/src/test/org/hibernate/test/annotations/onetomany/OneToManyTest.java
===================================================================
---
annotations/patches/JBPAPP-6940/src/test/org/hibernate/test/annotations/onetomany/OneToManyTest.java 2012-08-30
16:52:35 UTC (rev 21064)
+++
annotations/patches/JBPAPP-6940/src/test/org/hibernate/test/annotations/onetomany/OneToManyTest.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -79,10 +79,16 @@
s.flush();
s.clear();
- //testing @OrderBy with explicit values including Formula
+ // Assert the primary key value relationship amongst the 3 streets...
+ assertTrue( rochechoir.getId() < chmpsElysees.getId() );
+ assertTrue( chmpsElysees.getId() < grandeArmee.getId() );
paris = (City) s.get( City.class, paris.getId() );
+
+ // City.streets is defined to be ordered by name primarily...
assertEquals( 3, paris.getStreets().size() );
assertEquals( chmpsElysees.getStreetName(), paris.getStreets().get( 0 ).getStreetName()
);
+ assertEquals( grandeArmee.getStreetName(), paris.getStreets().get( 1 ).getStreetName()
);
+ // City.mainStreets is defined to be ordered by street id
List<Street> mainStreets = paris.getMainStreets();
assertEquals( 2, mainStreets.size() );
Integer previousId = new Integer( -1 );
@@ -381,7 +387,8 @@
tx.commit();
s.close();
}
- //known issue JBPAPP-1123 HHH-3577
+
+ // HHH-4394
public void testOrderByOnSuperclassProperty() {
if(getDialect() instanceof MySQLDialect || getDialect() instanceof PostgreSQLDialect ||
getDialect() instanceof SQLServerDialect|| getDialect() instanceof Oracle8iDialect){
log.warn("skip test testOrderByContractor due to JBPAPP-1123");
Property changes on: core/patches/JBPAPP-6940
___________________________________________________________________
Added: svn:ignore
+ .settings
build
.classpath
.project
Modified: core/patches/JBPAPP-6940/build.xml
===================================================================
--- core/patches/JBPAPP-6940/build.xml 2012-08-30 16:52:35 UTC (rev 21064)
+++ core/patches/JBPAPP-6940/build.xml 2012-08-30 16:55:39 UTC (rev 21065)
@@ -48,6 +48,7 @@
<property name="dir.out.test-classes"
value="${dir.build}/testclasses"/>
<property name="dir.out.generated-source"
value="${dir.build}/gensrc"/>
<property name="dir.out.antlr-package"
value="${dir.out.generated-source}/org/hibernate/hql/antlr"/>
+ <property name="dir.out.antlr-package.order-by"
value="${dir.out.generated-source}/org/hibernate/sql/ordering/antlr"/>
<property name="dir.out.junit"
value="${dir.build}/testout"/>
<property name="dir.out.junit-reports"
value="${dir.build}/test-reports"/>
<property name="dir.out.perf-test"
value="${dir.build}/testout-perf"/>
@@ -170,7 +171,8 @@
<target name="antlr" depends="init.antlr"
unless="antlr.isUpToDate" description="Generate ANTLR parsers.">
<mkdir dir="${dir.out.antlr-package}"/>
- <antlr target="${dir.grammar}/hql.g"
outputdirectory="${dir.out.antlr-package}">
+ <mkdir dir="${dir.out.antlr-package.order-by}"/>
+ <antlr target="${dir.grammar}/hql.g"
outputdirectory="${dir.out.antlr-package}">
<classpath refid="path.lib"/>
</antlr>
<antlr target="${dir.grammar}/hql-sql.g"
outputdirectory="${dir.out.antlr-package}">
@@ -179,6 +181,12 @@
<antlr target="${dir.grammar}/sql-gen.g"
outputdirectory="${dir.out.antlr-package}">
<classpath refid="path.lib"/>
</antlr>
+ <antlr target="${dir.grammar}/order-by.g"
outputdirectory="${dir.out.antlr-package.order-by}">
+ <classpath refid="path.lib"/>
+ </antlr>
+ <antlr target="${dir.grammar}/order-by-render.g"
outputdirectory="${dir.out.antlr-package.order-by}">
+ <classpath refid="path.lib"/>
+ </antlr>
<touch file="${dir.out.antlr-package}/.antlr_run"/>
</target>
Added: core/patches/JBPAPP-6940/grammar/order-by-render.g
===================================================================
--- core/patches/JBPAPP-6940/grammar/order-by-render.g (rev 0)
+++ core/patches/JBPAPP-6940/grammar/order-by-render.g 2012-08-30 16:55:39 UTC (rev
21065)
@@ -0,0 +1,92 @@
+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
+ */
+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();
+ }
+}
+
+orderByFragment
+ : #(
+ ORDER_BY sortSpecification ( {out(", ");} sortSpecification)*
+ )
+ ;
+
+sortSpecification
+ : #(
+ SORT_SPEC sortKeySpecification (collationSpecification)?
(orderingSpecification)?
+ )
+ ;
+
+sortKeySpecification
+ : #(SORT_KEY sortKey)
+ ;
+
+sortKey
+ : i:IDENT {
+ out( #i );
+ }
+ ;
+
+collationSpecification
+ : c:COLLATE {
+ out( " collate " );
+ out( c );
+ }
+ ;
+
+orderingSpecification
+ : o:ORDER_SPEC {
+ out( " " );
+ out( #o );
+ }
+ ;
\ No newline at end of file
Added: core/patches/JBPAPP-6940/grammar/order-by.g
===================================================================
--- core/patches/JBPAPP-6940/grammar/order-by.g (rev 0)
+++ core/patches/JBPAPP-6940/grammar/order-by.g 2012-08-30 16:55:39 UTC (rev 21065)
@@ -0,0 +1,440 @@
+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;
+ SORT_KEY;
+ EXPR_LIST;
+ DOT;
+ IDENT_LIST;
+ COLUMN_REF;
+
+ COLLATE="collate";
+ ASCENDING="asc";
+ DESCENDING="desc";
+}
+
+
+{
+ /**
+ * Method for logging execution trace information.
+ *
+ * @param msg The trace message.
+ */
+ 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 somtimes
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)? {
+ #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"] );
+ }
+ ;
+
+/**
+ * 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
+ ;
Modified: core/patches/JBPAPP-6940/src/org/hibernate/hql/ast/util/ASTPrinter.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/hql/ast/util/ASTPrinter.java 2012-08-30
16:52:35 UTC (rev 21064)
+++ core/patches/JBPAPP-6940/src/org/hibernate/hql/ast/util/ASTPrinter.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -149,7 +149,7 @@
* @return String - The token type name from the token type constant class,
* or just the integer as a string if none exists.
*/
- private String getTokenTypeName(int type) {
+ public String getTokenTypeName(int type) {
// If the class with the constants in it was not supplied, just
// use the integer token type as the token type name.
if ( tokenTypeConstants == null ) {
Modified:
core/patches/JBPAPP-6940/src/org/hibernate/persister/collection/AbstractCollectionPersister.java
===================================================================
---
core/patches/JBPAPP-6940/src/org/hibernate/persister/collection/AbstractCollectionPersister.java 2012-08-30
16:52:35 UTC (rev 21064)
+++
core/patches/JBPAPP-6940/src/org/hibernate/persister/collection/AbstractCollectionPersister.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -18,8 +18,6 @@
import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.TransientObjectException;
-import org.hibernate.jdbc.Expectation;
-import org.hibernate.jdbc.Expectations;
import org.hibernate.cache.CacheConcurrencyStrategy;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.entry.CacheEntryStructure;
@@ -30,14 +28,16 @@
import org.hibernate.collection.PersistentCollection;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.EntityKey;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.PersistenceContext;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.SubselectFetch;
-import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.exception.SQLExceptionConverter;
import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.jdbc.Expectation;
+import org.hibernate.jdbc.Expectations;
import org.hibernate.loader.collection.CollectionInitializer;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
@@ -51,11 +51,18 @@
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.PropertyMapping;
+import org.hibernate.persister.entity.Queryable;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.sql.Alias;
import org.hibernate.sql.SelectFragment;
import org.hibernate.sql.SimpleSelect;
import org.hibernate.sql.Template;
+import org.hibernate.sql.ordering.antlr.ColumnMapper;
+import org.hibernate.sql.ordering.antlr.ColumnReference;
+import org.hibernate.sql.ordering.antlr.FormulaReference;
+import org.hibernate.sql.ordering.antlr.OrderByAliasResolver;
+import org.hibernate.sql.ordering.antlr.OrderByTranslation;
+import org.hibernate.sql.ordering.antlr.SqlValueReference;
import org.hibernate.type.AbstractComponentType;
import org.hibernate.type.CollectionType;
import org.hibernate.type.EntityType;
@@ -89,14 +96,17 @@
private final String sqlDetectRowByIndexString;
private final String sqlDetectRowByElementString;
- private final String sqlOrderByString;
protected final String sqlWhereString;
- private final String sqlOrderByStringTemplate;
private final String sqlWhereStringTemplate;
- private final boolean hasOrder;
protected final boolean hasWhere;
private final int baseIndex;
+ private final boolean hasOrder;
+ private final OrderByTranslation orderByTranslation;
+
+ private final boolean hasManyToManyOrder;
+ private final OrderByTranslation manyToManyOrderByTranslation;
+
private final String nodeName;
private final String elementNodeName;
private final String indexNodeName;
@@ -173,9 +183,6 @@
private final String manyToManyWhereString;
private final String manyToManyWhereTemplate;
- private final String manyToManyOrderByString;
- private final String manyToManyOrderByTemplate;
-
// custom sql
private final boolean insertCallable;
private final boolean updateCallable;
@@ -243,12 +250,7 @@
for ( int i = 1; i < spacesSize; i++ ) {
spaces[i] = (String) iter.next();
}
-
- sqlOrderByString = collection.getOrderBy();
- hasOrder = sqlOrderByString != null;
- sqlOrderByStringTemplate = hasOrder ?
- Template.renderOrderByStringTemplate(sqlOrderByString, dialect,
factory.getSqlFunctionRegistry()) :
- null;
+
sqlWhereString = StringHelper.isNotEmpty( collection.getWhere() ) ? "( " +
collection.getWhere() + ") " : null;
hasWhere = sqlWhereString != null;
sqlWhereStringTemplate = hasWhere ?
@@ -517,6 +519,20 @@
);
}
}
+
+ hasOrder = collection.getOrderBy() != null;
+ if ( hasOrder ) {
+ orderByTranslation = Template.translateOrderBy(
+ collection.getOrderBy(),
+ new ColumnMapperImpl(),
+ factory,
+ dialect,
+ factory.getSqlFunctionRegistry()
+ );
+ }
+ else {
+ orderByTranslation = null;
+ }
// Handle any filters applied to this collection
filterHelper = new FilterHelper( collection.getFilterMap(), dialect,
factory.getSqlFunctionRegistry() );
@@ -529,14 +545,76 @@
manyToManyWhereTemplate = manyToManyWhereString == null ?
null :
Template.renderWhereStringTemplate( manyToManyWhereString, factory.getDialect(),
factory.getSqlFunctionRegistry() );
- manyToManyOrderByString = collection.getManyToManyOrdering();
- manyToManyOrderByTemplate = manyToManyOrderByString == null
- ? null
- : Template.renderOrderByStringTemplate( manyToManyOrderByString,
factory.getDialect(), factory.getSqlFunctionRegistry() );
+
+ hasManyToManyOrder = collection.getManyToManyOrdering() != null;
+ if ( hasManyToManyOrder ) {
+ manyToManyOrderByTranslation = Template.translateOrderBy(
+ collection.getManyToManyOrdering(),
+ new ColumnMapperImpl(),
+ factory,
+ dialect,
+ factory.getSqlFunctionRegistry()
+ );
+ }
+ else {
+ manyToManyOrderByTranslation = null;
+ }
initCollectionPropertyMap();
}
+
+ private class ColumnMapperImpl implements ColumnMapper {
+ public SqlValueReference[] map(String reference) {
+ final String[] columnNames;
+ final String[] formulaTemplates;
+ // handle the special "$element$" property name...
+ if ( "$element$".equals( reference ) ) {
+ columnNames = elementColumnNames;
+ formulaTemplates = elementFormulaTemplates;
+ }
+ else {
+ columnNames = elementPropertyMapping.toColumns( reference );
+ formulaTemplates = formulaTemplates( reference, columnNames.length );
+ }
+
+ final SqlValueReference[] result = new SqlValueReference[ columnNames.length ];
+ int i = 0;
+ for ( final String columnName : columnNames ) {
+ if ( columnName == null ) {
+ // if the column name is null, it indicates that this index in the property value
mapping is
+ // actually represented by a formula.
+ final int propertyIndex = elementPersister.getEntityMetamodel().getPropertyIndex(
reference );
+ final String formulaTemplate = formulaTemplates[i];
+ result[i] = new FormulaReference() {
+ public String getFormulaFragment() {
+ return formulaTemplate;
+ }
+ };
+ }
+ else {
+ result[i] = new ColumnReference() {
+ public String getColumnName() {
+ return columnName;
+ }
+ };
+ }
+ i++;
+ }
+ return result;
+ }
+ }
+
+ private String[] formulaTemplates(String reference, int expectedSize) {
+ try {
+ final int propertyIndex = elementPersister.getEntityMetamodel().getPropertyIndex(
reference );
+ return ( (Queryable) elementPersister
).getSubclassPropertyFormulaTemplateClosure()[propertyIndex];
+ }
+ catch (Exception e) {
+ return new String[expectedSize];
+ }
+ }
+
public void postInstantiate() throws MappingException {
initializer = queryLoaderName == null ?
createCollectionInitializer( CollectionHelper.EMPTY_MAP ) :
@@ -635,18 +713,17 @@
}
public String getSQLOrderByString(String alias) {
- return hasOrdering() ?
- StringHelper.replace( sqlOrderByStringTemplate, Template.TEMPLATE, alias ) :
"";
+ return hasOrdering()
+ ? orderByTranslation.injectAliases( new StandardOrderByAliasResolver( alias ) )
+ : "";
}
public String getManyToManyOrderByString(String alias) {
- if ( isManyToMany() && manyToManyOrderByString != null ) {
- return StringHelper.replace( manyToManyOrderByTemplate, Template.TEMPLATE, alias );
- }
- else {
- return "";
- }
+ return hasManyToManyOrdering()
+ ? manyToManyOrderByTranslation.injectAliases( new StandardOrderByAliasResolver( alias
) )
+ : "";
}
+
public FetchMode getFetchMode() {
return fetchMode;
}
@@ -656,7 +733,7 @@
}
public boolean hasManyToManyOrdering() {
- return isManyToMany() && manyToManyOrderByTemplate != null;
+ return isManyToMany() && hasManyToManyOrder;
}
public boolean hasWhere() {
@@ -1792,4 +1869,22 @@
public CollectionInitializer getInitializer() {
return initializer;
}
+
+ private class StandardOrderByAliasResolver implements OrderByAliasResolver {
+ private final String rootAlias;
+
+ private StandardOrderByAliasResolver(String rootAlias) {
+ this.rootAlias = rootAlias;
+ }
+
+ public String resolveTableAlias(String columnReference) {
+ if ( elementPersister == null ) {
+ // we have collection of non-entity elements...
+ return rootAlias;
+ }
+ else {
+ return ( (Loadable) elementPersister ).getTableAliasForColumn( columnReference,
rootAlias );
+ }
+ }
+ }
}
Modified:
core/patches/JBPAPP-6940/src/org/hibernate/persister/entity/AbstractEntityPersister.java
===================================================================
---
core/patches/JBPAPP-6940/src/org/hibernate/persister/entity/AbstractEntityPersister.java 2012-08-30
16:52:35 UTC (rev 21064)
+++
core/patches/JBPAPP-6940/src/org/hibernate/persister/entity/AbstractEntityPersister.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -1488,7 +1488,7 @@
return propertyDefinedOnSubclass[i];
}
- protected String[][] getSubclassPropertyFormulaTemplateClosure() {
+ public String[][] getSubclassPropertyFormulaTemplateClosure() {
return subclassPropertyFormulaTemplateClosure;
}
@@ -3844,6 +3844,13 @@
throws HibernateException {
getTuplizer( entityMode ).setPropertyValue( object, propertyName, value );
}
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ public String getTableAliasForColumn(String columnName, String rootAlias) {
+ return generateTableAlias( rootAlias, determineTableNumberForColumn( columnName ) );
+ }
+ public int determineTableNumberForColumn(String columnName) {
+ return 0;
+ }
+
}
Modified:
core/patches/JBPAPP-6940/src/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java
===================================================================
---
core/patches/JBPAPP-6940/src/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java 2012-08-30
16:52:35 UTC (rev 21064)
+++
core/patches/JBPAPP-6940/src/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -584,4 +584,24 @@
}
return super.getSubclassPropertyDeclarer( propertyPath );
}
+
+ @Override
+ public int determineTableNumberForColumn(String columnName) {
+ final String[] subclassColumnNameClosure = getSubclassColumnClosure();
+ for ( int i = 0, max = subclassColumnNameClosure.length; i < max; i++ ) {
+ final boolean quoted = subclassColumnNameClosure[i].startsWith( "\"" )
+ && subclassColumnNameClosure[i].endsWith( "\"" );
+ if ( quoted ) {
+ if ( subclassColumnNameClosure[i].equals( columnName ) ) {
+ return getSubclassColumnTableNumberClosure()[i];
+ }
+ }
+ else {
+ if ( subclassColumnNameClosure[i].equalsIgnoreCase( columnName ) ) {
+ return getSubclassColumnTableNumberClosure()[i];
+ }
+ }
+ }
+ throw new HibernateException( "Could not locate table which owns column [" +
columnName + "] referenced in order-by mapping" );
+ }
}
Modified: core/patches/JBPAPP-6940/src/org/hibernate/persister/entity/Loadable.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/persister/entity/Loadable.java 2012-08-30
16:52:35 UTC (rev 21064)
+++ core/patches/JBPAPP-6940/src/org/hibernate/persister/entity/Loadable.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -85,4 +85,18 @@
public boolean isAbstract();
+ /**
+ * Given a column name and the root table alias in use for the entity hierarchy,
determine the proper table alias
+ * for the table in that hierarchy that contains said column.
+ * <p/>
+ * NOTE : Generally speaking the column is not validated to exist. Most implementations
simply return the
+ * root alias; the exception is {@link JoinedSubclassEntityPersister}
+ *
+ * @param columnName The column name
+ * @param rootAlias The hierarchy root alias
+ *
+ * @return The proper table alias for qualifying the given column.
+ */
+ public String getTableAliasForColumn(String columnName, String rootAlias);
+
}
Modified: core/patches/JBPAPP-6940/src/org/hibernate/persister/entity/Queryable.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/persister/entity/Queryable.java 2012-08-30
16:52:35 UTC (rev 21064)
+++ core/patches/JBPAPP-6940/src/org/hibernate/persister/entity/Queryable.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -139,6 +139,8 @@
*/
public String generateFilterConditionAlias(String rootAlias);
+ String[][] getSubclassPropertyFormulaTemplateClosure();
+
public static class Declarer {
public static final Declarer CLASS = new Declarer( "class" );
public static final Declarer SUBCLASS = new Declarer( "subclass" );
Modified: core/patches/JBPAPP-6940/src/org/hibernate/sql/Template.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/sql/Template.java 2012-08-30 16:52:35 UTC
(rev 21064)
+++ core/patches/JBPAPP-6940/src/org/hibernate/sql/Template.java 2012-08-30 16:55:39 UTC
(rev 21065)
@@ -6,6 +6,13 @@
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.function.SQLFunctionRegistry;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.sql.ordering.antlr.ColumnMapper;
+import org.hibernate.sql.ordering.antlr.OrderByAliasResolver;
+import org.hibernate.sql.ordering.antlr.OrderByFragmentTranslator;
+import org.hibernate.sql.ordering.antlr.OrderByTranslation;
+import org.hibernate.sql.ordering.antlr.SqlValueReference;
+import org.hibernate.sql.ordering.antlr.TranslationContext;
import org.hibernate.util.StringHelper;
/**
@@ -208,93 +215,105 @@
return result.toString();
}
+
+
+ public static class NoOpColumnMapper implements ColumnMapper {
+ public static final NoOpColumnMapper INSTANCE = new NoOpColumnMapper();
+ public SqlValueReference[] map(String reference) {
+ // return new String[] { reference };
+ return null;
+ }
+ }
+
/**
- * Takes order by clause provided in the mapping attribute and interpolates the alias.
- * Handles asc, desc, SQL functions, quoted identifiers.
+ * Performs order-by template rendering without {@link ColumnMapper column mapping}. An
<tt>ORDER BY</tt> template
+ * has all column references "qualified" with a placeholder identified by
{@link Template#TEMPLATE}
+ *
+ * @param orderByFragment The order-by fragment to render.
+ * @param dialect The SQL dialect being used.
+ * @param functionRegistry The SQL function registry
+ *
+ * @return The rendered <tt>ORDER BY</tt> template.
+ *
+ * @deprecated Use {@link #translateOrderBy} instead
*/
- public static String renderOrderByStringTemplate(String sqlOrderByString, Dialect
dialect, SQLFunctionRegistry functionRegistry) {
- //TODO: make this a bit nicer
- String symbols = new StringBuffer()
- .append("=><!+-*/()',|&`")
- .append(StringHelper.WHITESPACE)
- .append( dialect.openQuote() )
- .append( dialect.closeQuote() )
- .toString();
- StringTokenizer tokens = new StringTokenizer(sqlOrderByString, symbols, true);
-
- StringBuffer result = new StringBuffer();
- boolean quoted = false;
- boolean quotedIdentifier = false;
-
- boolean hasMore = tokens.hasMoreTokens();
- String nextToken = hasMore ? tokens.nextToken() : null;
- while (hasMore) {
- String token = nextToken;
- String lcToken = token.toLowerCase();
- hasMore = tokens.hasMoreTokens();
- nextToken = hasMore ? tokens.nextToken() : null;
-
- boolean isQuoteCharacter = false;
-
- if ( !quotedIdentifier && "'".equals(token) ) {
- quoted = !quoted;
- isQuoteCharacter = true;
+ @Deprecated
+ public static String renderOrderByStringTemplate(
+ String orderByFragment,
+ Dialect dialect,
+ SQLFunctionRegistry functionRegistry) {
+ return renderOrderByStringTemplate(
+ orderByFragment,
+ NoOpColumnMapper.INSTANCE,
+ null,
+ dialect,
+ functionRegistry
+ );
+ }
+
+ public static String renderOrderByStringTemplate(
+ String orderByFragment,
+ final ColumnMapper columnMapper,
+ final SessionFactoryImplementor sessionFactory,
+ final Dialect dialect,
+ final SQLFunctionRegistry functionRegistry) {
+ return translateOrderBy(
+ orderByFragment,
+ columnMapper,
+ sessionFactory,
+ dialect,
+ functionRegistry
+ ).injectAliases( LEGACY_ORDER_BY_ALIAS_RESOLVER );
+ }
+
+ public static OrderByAliasResolver LEGACY_ORDER_BY_ALIAS_RESOLVER = new
OrderByAliasResolver() {
+ public String resolveTableAlias(String columnReference) {
+ return TEMPLATE;
+ }
+ };
+
+ /**
+ * Performs order-by template rendering allowing {@link ColumnMapper column mapping}. An
<tt>ORDER BY</tt> template
+ * has all column references "qualified" with a placeholder identified by
{@link Template#TEMPLATE} which can later
+ * be used to easily inject the SQL alias.
+ *
+ * @param orderByFragment The order-by fragment to render.
+ * @param columnMapper The column mapping strategy to use.
+ * @param sessionFactory The session factory.
+ * @param dialect The SQL dialect being used.
+ * @param functionRegistry The SQL function registry
+ *
+ * @return The rendered <tt>ORDER BY</tt> template.
+ */
+ public static OrderByTranslation translateOrderBy(
+ String orderByFragment,
+ final ColumnMapper columnMapper,
+ final SessionFactoryImplementor sessionFactory,
+ final Dialect dialect,
+ final SQLFunctionRegistry functionRegistry) {
+ TranslationContext context = new TranslationContext() {
+ public SessionFactoryImplementor getSessionFactory() {
+ return sessionFactory;
}
-
- if ( !quoted ) {
-
- boolean isOpenQuote;
- if ( "`".equals(token) ) {
- isOpenQuote = !quotedIdentifier;
- token = lcToken = isOpenQuote ?
- new Character( dialect.openQuote() ).toString() :
- new Character( dialect.closeQuote() ).toString();
- quotedIdentifier = isOpenQuote;
- isQuoteCharacter = true;
- }
- else if ( !quotedIdentifier && ( dialect.openQuote()==token.charAt(0) ) ) {
- isOpenQuote = true;
- quotedIdentifier = true;
- isQuoteCharacter = true;
- }
- else if ( quotedIdentifier && ( dialect.closeQuote()==token.charAt(0) ) ) {
- quotedIdentifier = false;
- isQuoteCharacter = true;
- isOpenQuote = false;
- }
- else {
- isOpenQuote = false;
- }
-
- if (isOpenQuote) {
- result.append(TEMPLATE).append('.');
- }
-
+
+ public Dialect getDialect() {
+ return dialect;
}
-
- boolean quotedOrWhitespace = quoted ||
- quotedIdentifier ||
- isQuoteCharacter ||
- Character.isWhitespace( token.charAt(0) );
-
- if (quotedOrWhitespace) {
- result.append(token);
+
+ public SQLFunctionRegistry getSqlFunctionRegistry() {
+ return functionRegistry;
}
- else if (
- isIdentifier(token, dialect) &&
- !isFunctionOrKeyword(lcToken, nextToken, dialect, functionRegistry)
- ) {
- result.append(TEMPLATE)
- .append('.')
- .append( dialect.quote(token) );
+
+ public ColumnMapper getColumnMapper() {
+ return columnMapper;
}
- else {
- result.append(token);
- }
- }
- return result.toString();
+ };
+
+ return OrderByFragmentTranslator.translate( context, orderByFragment );
}
+
+
private static boolean isNamedParameter(String token) {
return token.startsWith(":");
}
Added:
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/CollationSpecification.java
===================================================================
---
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/CollationSpecification.java
(rev 0)
+++
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/CollationSpecification.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,33 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008 Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+/**
+ * Models a collation specification (<tt>COLLATE</tt> using a specific
character-set) within a
+ * {@link SortSpecification}.
+ *
+ * @author Steve Ebersole
+ */
+public class CollationSpecification extends NodeSupport {
+}
Added: core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/ColumnMapper.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/ColumnMapper.java
(rev 0)
+++
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/ColumnMapper.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,46 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008 Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+import org.hibernate.HibernateException;
+
+/**
+ * Contract for mapping a (an assumed) property reference to its columns.
+ *
+ * @author Steve Ebersole
+ */
+public interface ColumnMapper {
+ /**
+ * Resolve the property reference to its underlying columns.
+ *
+ * @param reference The property reference name.
+ *
+ * @return References to the columns/formulas that define the value mapping for the
given property, or null
+ * if the property reference is unknown.
+ *
+ * @throws HibernateException Generally indicates that the property reference is
unknown; interpretation
+ * should be the same as a null return.
+ */
+ public SqlValueReference[] map(String reference) throws HibernateException;
+}
Added: core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/ColumnReference.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/ColumnReference.java
(rev 0)
+++
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/ColumnReference.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,38 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+/**
+ * Reference to a column name.
+ *
+ * @author Steve Ebersole
+ */
+public interface ColumnReference extends SqlValueReference {
+ /**
+ * Retrieve the column name.
+ *
+ * @return THe column name
+ */
+ public String getColumnName();
+}
Added: core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/Factory.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/Factory.java
(rev 0)
+++ core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/Factory.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,51 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008 Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+import antlr.ASTFactory;
+
+/**
+ * Acts as a {@link ASTFactory} for injecting our specific AST node classes into the
Antlr generated trees.
+ *
+ * @author Steve Ebersole
+ */
+public class Factory extends ASTFactory implements OrderByTemplateTokenTypes {
+ @Override
+ public Class getASTNodeType(int i) {
+ switch ( i ) {
+ case ORDER_BY:
+ return OrderByFragment.class;
+ case SORT_SPEC:
+ return SortSpecification.class;
+ case ORDER_SPEC:
+ return OrderingSpecification.class;
+ case COLLATE:
+ return CollationSpecification.class;
+ case SORT_KEY:
+ return SortKey.class;
+ default:
+ return NodeSupport.class;
+ }
+ }
+}
Added:
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/FormulaReference.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/FormulaReference.java
(rev 0)
+++
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/FormulaReference.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,40 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+/**
+ * Reference to a formula fragment.
+ *
+ * @author Steve Ebersole
+ */
+public interface FormulaReference extends SqlValueReference {
+ /**
+ * Retrieve the formula fragment. It is important to note that this is what the
persister calls the
+ * "formula template", which has the $PlaceHolder$ (see {@link
org.hibernate.sql.Template#TEMPLATE})
+ * markers injected.
+ *
+ * @return The formula fragment template.
+ */
+ public String getFormulaFragment();
+}
Added: core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/Node.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/Node.java
(rev 0)
+++ core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/Node.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,52 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008 Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+/**
+ * General contract for AST nodes.
+ *
+ * @author Steve Ebersole
+ */
+public interface Node {
+ /**
+ * Get the intrinsic text of this node.
+ *
+ * @return The node's text.
+ */
+ public String getText();
+
+ /**
+ * Get a string representation of this node usable for debug logging or similar.
+ *
+ * @return The node's debugging text.
+ */
+ public String getDebugText();
+
+ /**
+ * Build the node's representation for use in the resulting rendering.
+ *
+ * @return The text for use in the translated output.
+ */
+ public String getRenderableText();
+}
Added: core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/NodeSupport.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/NodeSupport.java
(rev 0)
+++
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/NodeSupport.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,41 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+import antlr.CommonAST;
+
+/**
+ * Basic implementation of a {@link Node} briding to the Antlr {@link CommonAST}
hierarchy.
+ *
+ * @author Steve Ebersole
+ */
+public class NodeSupport extends CommonAST implements Node {
+ public String getDebugText() {
+ return getText();
+ }
+
+ public String getRenderableText() {
+ return getText();
+ }
+}
Added:
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByAliasResolver.java
===================================================================
---
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByAliasResolver.java
(rev 0)
+++
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByAliasResolver.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,35 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+/**
+ * Given a column reference, resolve the table alias to apply to the column to qualify
it.
+ */
+public interface OrderByAliasResolver {
+ /**
+ * Given a column reference, resolve the table alias to apply to the column to qualify
it.
+ *
+ */
+ public String resolveTableAlias(String columnReference);
+}
Added: core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByFragment.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByFragment.java
(rev 0)
+++
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByFragment.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,32 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008 Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+/**
+ * Represents a parsed <tt>order-by</tt> mapping fragment. This holds the
tree of all {@link SortSpecification}s.
+ *
+ * @author Steve Ebersole
+ */
+public class OrderByFragment extends NodeSupport {
+}
Added:
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByFragmentParser.java
===================================================================
---
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByFragmentParser.java
(rev 0)
+++
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByFragmentParser.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,333 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008 Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.hibernate.dialect.function.SQLFunction;
+import org.hibernate.sql.Template;
+import org.hibernate.util.StringHelper;
+import org.jboss.logging.Logger;
+
+import antlr.CommonAST;
+import antlr.TokenStream;
+import antlr.collections.AST;
+
+/**
+ * Extension of the Antlr-generated parser for the purpose of adding our custom parsing
behavior
+ * (semantic analysis, etc).
+ *
+ * @author Steve Ebersole
+ */
+public class OrderByFragmentParser extends GeneratedOrderByFragmentParser {
+ private static final Logger LOG =
Logger.getLogger(OrderByFragmentParser.class.getName());
+
+ private final TranslationContext context;
+
+ private Set<String> columnReferences = new HashSet<String>();
+
+ public OrderByFragmentParser(TokenStream lexer, TranslationContext context) {
+ super( lexer );
+ super.setASTFactory( new Factory() );
+ this.context = context;
+ }
+
+ public Set<String> getColumnReferences() {
+ return columnReferences;
+ }
+
+ @Override
+ protected AST quotedIdentifier(AST ident) {
+ /*
+ * Semantic action used during recognition of quoted identifiers (quoted column names)
+ */
+ final String columnName = context.getDialect().quote( '`' + ident.getText() +
'`' );
+ columnReferences.add( columnName );
+ final String marker = '{' + columnName + '}';
+ return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, marker );
+ }
+
+ @Override
+ protected AST quotedString(AST ident) {
+ /*
+ * Semantic action used during recognition of quoted strings (string literals)
+ */
+ return getASTFactory().create( OrderByTemplateTokenTypes.IDENT,
context.getDialect().quote( ident.getText() ) );
+ }
+
+ @Override
+ @SuppressWarnings("SimplifiableIfStatement")
+ protected boolean isFunctionName(AST ast) {
+ /*
+ * Semantic predicate used to determine whether a given AST node represents a function
call
+ */
+
+ AST child = ast.getFirstChild();
+ // assume it is a function if it has parameters
+ if ( child != null && "{param list}".equals( child.getText() ) ) {
+ return true;
+ }
+
+ // otherwise, in order for this to be a function logically it has to be a function that
does not
+ // have arguments. So try to assert that using the registry of known functions
+ final SQLFunction function = context.getSqlFunctionRegistry().findSQLFunction(
ast.getText() );
+ if ( function == null ) {
+ // no registered function, so we cannot know for certain
+ return false;
+ }
+ else {
+ // if function.hasParenthesesIfNoArguments() is true, then assume the node is not a
function
+ return ! function.hasParenthesesIfNoArguments();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected AST resolveFunction(AST ast) {
+ /*
+ * Semantic action used during recognition of a *known* function
+ */
+ AST child = ast.getFirstChild();
+ if ( child != null ) {
+ assert "{param list}".equals( child.getText() );
+ child = child.getFirstChild();
+ }
+
+ final String functionName = ast.getText();
+ final SQLFunction function = context.getSqlFunctionRegistry().findSQLFunction(
functionName );
+ if ( function == null ) {
+ String text = functionName;
+ if ( child != null ) {
+ text += '(';
+ while ( child != null ) {
+ text += resolveFunctionArgument( child );
+ child = child.getNextSibling();
+ if ( child != null ) {
+ text += ", ";
+ }
+ }
+ text += ')';
+ }
+ return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, text );
+ }
+ else {
+ ArrayList expressions = new ArrayList();
+ while ( child != null ) {
+ expressions.add( resolveFunctionArgument( child ) );
+ child = child.getNextSibling();
+ }
+ final String text = function.render( expressions, context.getSessionFactory() );
+ return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, text );
+ }
+ }
+
+ private String resolveFunctionArgument(AST argumentNode) {
+ final String nodeText = argumentNode.getText();
+ final String adjustedText;
+ if ( nodeText.contains( Template.TEMPLATE ) ) {
+ // we have a SQL order-by fragment
+ adjustedText = adjustTemplateReferences( nodeText );
+ }
+ else if ( nodeText.startsWith( "{" ) && nodeText.endsWith(
"}" ) ) {
+ columnReferences.add( nodeText.substring( 1, nodeText.length() - 1 ) );
+ return nodeText;
+ }
+ else {
+ adjustedText = nodeText;
+ // because we did not process the node text, we need to attempt to find any column
references
+ // contained in it.
+ // NOTE : uses regex for the time being; we should check the performance of this
+ Pattern pattern = Pattern.compile( "\\{(.*)\\}" );
+ Matcher matcher = pattern.matcher( adjustedText );
+ while ( matcher.find() ) {
+ columnReferences.add( matcher.group( 1 ) );
+ }
+ }
+ return adjustedText;
+ }
+
+ @Override
+ protected AST resolveIdent(AST ident) {
+ /*
+ * Semantic action used during recognition of an identifier. This identifier might be
a column name, it might
+ * be a property name.
+ */
+ String text = ident.getText();
+ SqlValueReference[] sqlValueReferences;
+ try {
+ sqlValueReferences = context.getColumnMapper().map( text );
+ }
+ catch( Throwable t ) {
+ sqlValueReferences = null;
+ }
+
+ if ( sqlValueReferences == null || sqlValueReferences.length == 0 ) {
+ return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, makeColumnReference(
text ) );
+ }
+ else if ( sqlValueReferences.length == 1 ) {
+ return processSqlValueReference( sqlValueReferences[0] );
+ }
+ else {
+ final AST root = getASTFactory().create( OrderByTemplateTokenTypes.IDENT_LIST,
"{ident list}" );
+ for ( SqlValueReference sqlValueReference : sqlValueReferences ) {
+ root.addChild( processSqlValueReference( sqlValueReference ) );
+ }
+ return root;
+ }
+ }
+
+ private AST processSqlValueReference(SqlValueReference sqlValueReference) {
+ if ( ColumnReference.class.isInstance( sqlValueReference ) ) {
+ final String columnName = ( (ColumnReference) sqlValueReference ).getColumnName();
+ return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, makeColumnReference(
columnName ) );
+ }
+ else {
+ final String formulaFragment = ( (FormulaReference) sqlValueReference
).getFormulaFragment();
+ // formulas have already been "adjusted" for aliases by appending
Template.TEMPLATE to places
+ // where we believe column references are. Fixing that is beyond scope of this work.
But we need
+ // to re-adjust that to use the order-by expectation of wrapping the column names in
curly
+ // braces (i.e., `{column_name}`).
+ final String adjustedText = adjustTemplateReferences( formulaFragment );
+ return getASTFactory().create( OrderByTemplateTokenTypes.IDENT, adjustedText );
+ }
+ }
+
+ private String makeColumnReference(String text) {
+ columnReferences.add( text );
+ return "{" + text + "}";
+ }
+
+ private static final int TEMPLATE_MARKER_LENGTH = Template.TEMPLATE.length();
+
+ private String adjustTemplateReferences(String template) {
+ int templateLength = template.length();
+ int startPos = template.indexOf( Template.TEMPLATE );
+ while ( startPos < templateLength ) {
+ int dotPos = startPos + TEMPLATE_MARKER_LENGTH;
+
+ // from here we need to seek the end of the qualified identifier
+ int pos = dotPos + 1;
+ while ( pos < templateLength && isValidIdentifierCharacter(
template.charAt( pos ) ) ) {
+ pos++;
+ }
+
+ // At this point we know all 3 points in the template that are needed for
replacement.
+ // Basically we will be replacing the whole match with the bit following the dot, but
will wrap
+ // the replacement in curly braces.
+ final String columnReference = template.substring( dotPos + 1, pos );
+ final String replacement = "{" + columnReference + "}";
+ template = template.replace( template.substring( startPos, pos ), replacement );
+ columnReferences.add( columnReference );
+
+ // prep for the next seek
+ startPos = ( pos - TEMPLATE_MARKER_LENGTH ) + 1;
+ templateLength = template.length();
+ }
+
+ return template;
+ }
+
+ private static boolean isValidIdentifierCharacter(char c) {
+ return Character.isLetter( c )
+ || Character.isDigit( c )
+ || '_' == c
+ || '\"' == c;
+ }
+
+ @Override
+ protected AST postProcessSortSpecification(AST sortSpec) {
+ assert SORT_SPEC == sortSpec.getType();
+ SortSpecification sortSpecification = ( SortSpecification ) sortSpec;
+ AST sortKey = sortSpecification.getSortKey();
+ if ( IDENT_LIST == sortKey.getFirstChild().getType() ) {
+ AST identList = sortKey.getFirstChild();
+ AST ident = identList.getFirstChild();
+ AST holder = new CommonAST();
+ do {
+ holder.addChild(
+ createSortSpecification(
+ ident,
+ sortSpecification.getCollation(),
+ sortSpecification.getOrdering()
+ )
+ );
+ ident = ident.getNextSibling();
+ } while ( ident != null );
+ sortSpec = holder.getFirstChild();
+ }
+ return sortSpec;
+ }
+
+ private SortSpecification createSortSpecification(
+ AST ident,
+ CollationSpecification collationSpecification,
+ OrderingSpecification orderingSpecification) {
+ AST sortSpecification = getASTFactory().create( SORT_SPEC, "{{sort
specification}}" );
+ AST sortKey = getASTFactory().create( SORT_KEY, "{{sort key}}" );
+ AST newIdent = getASTFactory().create( ident.getType(), ident.getText() );
+ sortKey.setFirstChild( newIdent );
+ sortSpecification.setFirstChild( sortKey );
+ if ( collationSpecification != null ) {
+ sortSpecification.addChild( collationSpecification );
+ }
+ if ( orderingSpecification != null ) {
+ sortSpecification.addChild( orderingSpecification );
+ }
+ return ( SortSpecification ) sortSpecification;
+ }
+
+
+
+ // trace logging
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ private int traceDepth = 0;
+
+
+ @Override
+ public void traceIn(String ruleName) {
+ if ( inputState.guessing > 0 ) {
+ return;
+ }
+ String prefix = StringHelper.repeat( '-', (traceDepth++ * 2) ) + "->
";
+ LOG.trace(prefix + ruleName);
+ }
+
+ @Override
+ public void traceOut(String ruleName) {
+ if ( inputState.guessing > 0 ) {
+ return;
+ }
+ String prefix = "<-" + StringHelper.repeat( '-', (--traceDepth *
2) ) + " ";
+ LOG.trace(prefix + ruleName);
+ }
+
+ @Override
+ protected void trace(String msg) {
+ LOG.trace( msg );
+ }
+}
Added:
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByFragmentRenderer.java
===================================================================
---
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByFragmentRenderer.java
(rev 0)
+++
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByFragmentRenderer.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,78 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008 Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+import org.hibernate.hql.ast.util.ASTPrinter;
+import org.hibernate.util.StringHelper;
+import org.jboss.logging.Logger;
+
+import antlr.collections.AST;
+
+/**
+ * Extension of the Antlr-generated tree walker for rendering the parsed order-by tree
back to String form.
+ * {@link #out(antlr.collections.AST)} is the sole semantic action here and it is used to
utilize our
+ * split between text (tree debugging text) and "renderable text" (text to use
during rendering).
+ *
+ * @author Steve Ebersole
+ */
+public class OrderByFragmentRenderer extends GeneratedOrderByFragmentRenderer {
+
+ private static final Logger LOG = Logger.getLogger(
OrderByFragmentRenderer.class.getName() );
+ private static final ASTPrinter printer = new ASTPrinter(
GeneratedOrderByFragmentRendererTokenTypes.class );
+
+ @Override
+ protected void out(AST ast) {
+ out( ( ( Node ) ast ).getRenderableText() );
+ }
+
+
+ // handle trace logging
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ private int traceDepth = 0;
+
+ @Override
+ public void traceIn(String ruleName, AST tree) {
+ if ( inputState.guessing > 0 ) {
+ return;
+ }
+ String prefix = StringHelper.repeat( '-', (traceDepth++ * 2) ) + "->
";
+ String traceText = ruleName + " (" + buildTraceNodeName(tree) +
")";
+ LOG.trace( prefix + traceText );
+ }
+
+ private String buildTraceNodeName(AST tree) {
+ return tree == null
+ ? "???"
+ : tree.getText() + " [" + printer.getTokenTypeName( tree.getType() ) +
"]";
+ }
+
+ @Override
+ public void traceOut(String ruleName, AST tree) {
+ if ( inputState.guessing > 0 ) {
+ return;
+ }
+ String prefix = "<-" + StringHelper.repeat( '-', (--traceDepth *
2) ) + " ";
+ LOG.trace( prefix + ruleName );
+ }
+}
Added:
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByFragmentTranslator.java
===================================================================
---
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByFragmentTranslator.java
(rev 0)
+++
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByFragmentTranslator.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,112 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008 Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+import java.io.StringReader;
+import java.util.Set;
+
+import org.hibernate.HibernateException;
+import org.hibernate.hql.ast.util.ASTPrinter;
+import org.jboss.logging.Logger;
+
+/**
+ * A translator for order-by mappings, whether specified by hbm.xml files, Hibernate
+ * {@link org.hibernate.annotations.OrderBy} annotation or JPA {@link
javax.persistence.OrderBy} annotation.
+ *
+ * @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.
+ * <p/>
+ * The important distinction to this split between (1) translating and (2) resolving
aliases is that
+ * both happen at different times
+ *
+ *
+ * @param context Context giving access to delegates needed during translation.
+ * @param fragment The user-supplied order-by fragment
+ *
+ * @return The translation.
+ */
+ public static OrderByTranslation translate(TranslationContext context, String fragment)
{
+ GeneratedOrderByLexer lexer = new GeneratedOrderByLexer( new StringReader( fragment )
);
+
+ // Perform the parsing (and some analysis/resolution). Another important aspect is the
collection
+ // of "column references" which are important later to seek out replacement
points in the
+ // translated fragment.
+ OrderByFragmentParser parser = new OrderByFragmentParser( lexer, context );
+ try {
+ parser.orderByFragment();
+ }
+ catch ( HibernateException e ) {
+ throw e;
+ }
+ catch ( Throwable t ) {
+ throw new HibernateException( "Unable to parse order-by fragment", t );
+ }
+
+ if ( LOG.isTraceEnabled() ) {
+ ASTPrinter printer = new ASTPrinter( OrderByTemplateTokenTypes.class );
+ LOG.trace( printer.showAsString( parser.getAST(), "--- {order-by fragment}
---" ) );
+ }
+
+ // Render the parsed tree to text.
+ OrderByFragmentRenderer renderer = new OrderByFragmentRenderer();
+ try {
+ renderer.orderByFragment( parser.getAST() );
+ }
+ catch ( HibernateException e ) {
+ throw e;
+ }
+ catch ( Throwable t ) {
+ throw new HibernateException( "Unable to render parsed order-by fragment", t
);
+ }
+
+ return new StandardOrderByTranslationImpl( renderer.getRenderedFragment(),
parser.getColumnReferences() );
+ }
+
+ public static class StandardOrderByTranslationImpl implements OrderByTranslation {
+ private final String sqlTemplate;
+ private final Set<String> columnReferences;
+
+ public StandardOrderByTranslationImpl(String sqlTemplate, Set<String>
columnReferences) {
+ this.sqlTemplate = sqlTemplate;
+ this.columnReferences = columnReferences;
+ }
+
+ public String injectAliases(OrderByAliasResolver aliasResolver) {
+ String sql = sqlTemplate;
+ for ( String columnReference : columnReferences ) {
+ final String replacementToken = "{" + columnReference + "}";
+ sql = sql.replace(
+ replacementToken,
+ aliasResolver.resolveTableAlias( columnReference ) + '.' + columnReference
+ );
+ }
+ return sql;
+ }
+ }
+}
Added:
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByTranslation.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByTranslation.java
(rev 0)
+++
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderByTranslation.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,41 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+/**
+ * Represents the result of an order-by translation by {@link @OrderByTranslator}
+ *
+ * @author Steve Ebersole
+ */
+public interface OrderByTranslation {
+ /**
+ * 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.
+ */
+ public String injectAliases(OrderByAliasResolver aliasResolver);
+}
Added:
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderingSpecification.java
===================================================================
---
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderingSpecification.java
(rev 0)
+++
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/OrderingSpecification.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,69 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008 Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+/**
+ * Models an ordering specification (<tt>ASCENDING</tt> or
<tt>DESCENDING</tt>) within a {@link SortSpecification}.
+ *
+ * @author Steve Ebersole
+ */
+public class OrderingSpecification extends NodeSupport {
+ public static class Ordering {
+ public static final Ordering ASCENDING = new Ordering( "asc" );
+ public static final Ordering DESCENDING = new Ordering( "desc" );
+
+ private final String name;
+
+ private Ordering(String name) {
+ this.name = name;
+ }
+ }
+
+ private boolean resolved;
+ private Ordering ordering;
+
+ public Ordering getOrdering() {
+ if ( !resolved ) {
+ ordering = resolve( getText() );
+ resolved = true;
+ }
+ return ordering;
+ }
+
+ private static Ordering resolve(String text) {
+ if ( Ordering.ASCENDING.name.equals( text ) ) {
+ return Ordering.ASCENDING;
+ }
+ else if ( Ordering.DESCENDING.name.equals( text ) ) {
+ return Ordering.DESCENDING;
+ }
+ else {
+ throw new IllegalStateException( "Unknown ordering [" + text + "]"
);
+ }
+ }
+
+ public String getRenderableText() {
+ return getOrdering().name;
+ }
+}
Added: core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/SortKey.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/SortKey.java
(rev 0)
+++ core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/SortKey.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,34 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008 Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+
+/**
+ * Models the container node for the <tt>sort key</tt>, which is the term
given by the ANSI SQL specification to the
+ * expression upon which to sort for each {@link SortSpecification}
+ *
+ * @author Steve Ebersole
+ */
+public class SortKey extends NodeSupport {
+}
Added:
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/SortSpecification.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/SortSpecification.java
(rev 0)
+++
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/SortSpecification.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,79 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008 Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+import antlr.collections.AST;
+
+/**
+ * Models each sorting expression.
+ *
+ * @author Steve Ebersole
+ */
+public class SortSpecification extends NodeSupport {
+ /**
+ * Locate the specified {@link SortKey}.
+ *
+ * @return The sort key.
+ */
+ public SortKey getSortKey() {
+ return ( SortKey ) getFirstChild();
+ }
+
+ /**
+ * Locate the specified <tt>collation specification</tt>, if one.
+ *
+ * @return The <tt>collation specification</tt>, or null if none was
specified.
+ */
+ public CollationSpecification getCollation() {
+ AST possible = getSortKey().getNextSibling();
+ return possible != null && OrderByTemplateTokenTypes.COLLATE ==
possible.getType()
+ ? ( CollationSpecification ) possible
+ : null;
+ }
+
+ /**
+ * Locate the specified <tt>ordering specification</tt>, if one.
+ *
+ * @return The <tt>ordering specification</tt>, or null if none was
specified.
+ */
+ public OrderingSpecification getOrdering() {
+ // IMPL NOTE : the ordering-spec would be either the 2nd or 3rd child (of the overall
sort-spec), if it existed,
+ // depending on whether a collation-spec was specified.
+
+ AST possible = getSortKey().getNextSibling();
+ if ( possible == null ) {
+ // There was no sort-spec parts specified other then the sort-key so there can be no
ordering-spec...
+ return null;
+ }
+
+ if ( OrderByTemplateTokenTypes.COLLATE == possible.getType() ) {
+ // the 2nd child was a collation-spec, so we need to check the 3rd child instead.
+ possible = possible.getNextSibling();
+ }
+
+ return possible != null && OrderByTemplateTokenTypes.ORDER_SPEC ==
possible.getType()
+ ? ( OrderingSpecification ) possible
+ : null;
+ }
+}
Added:
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/SqlValueReference.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/SqlValueReference.java
(rev 0)
+++
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/SqlValueReference.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,36 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2012, Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+/**
+ * Unifying interface between column and formula references mainly to give more strictly
typed result
+ * to {@link ColumnMapper#map(String)}
+ *
+ * @see ColumnReference
+ * @see FormulaReference
+ *
+ * @author Steve Ebersole
+ */
+public interface SqlValueReference {
+}
Added:
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/TranslationContext.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/TranslationContext.java
(rev 0)
+++
core/patches/JBPAPP-6940/src/org/hibernate/sql/ordering/antlr/TranslationContext.java 2012-08-30
16:55:39 UTC (rev 21065)
@@ -0,0 +1,63 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008 Red Hat Inc. 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 Inc.
+ *
+ * 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;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.function.SQLFunctionRegistry;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * Contract for contextual information required to perform translation.
+*
+* @author Steve Ebersole
+*/
+public interface TranslationContext {
+ /**
+ * Retrieves the <tt>session factory</tt> for this context.
+ *
+ * @return The <tt>session factory</tt>
+ */
+ public SessionFactoryImplementor getSessionFactory();
+
+ /**
+ * Retrieves the <tt>dialect</tt> for this context.
+ *
+ * @return The <tt>dialect</tt>
+ */
+ public Dialect getDialect();
+
+ /**
+ * Retrieves the <tt>SQL function registry/tt> for this context.
+ *
+ * @return The SQL function registry.
+ */
+ public SQLFunctionRegistry getSqlFunctionRegistry();
+
+ /**
+ * Retrieves the <tt>column mapper</tt> for this context.
+ *
+ * @return The <tt>column mapper</tt>
+ */
+ public ColumnMapper getColumnMapper();
+}
Modified: core/patches/JBPAPP-6940/src/org/hibernate/util/StringHelper.java
===================================================================
--- core/patches/JBPAPP-6940/src/org/hibernate/util/StringHelper.java 2012-08-30 16:52:35
UTC (rev 21064)
+++ core/patches/JBPAPP-6940/src/org/hibernate/util/StringHelper.java 2012-08-30 16:55:39
UTC (rev 21065)
@@ -1,9 +1,10 @@
//$Id$
package org.hibernate.util;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.StringTokenizer;
-import java.util.ArrayList;
public final class StringHelper {
@@ -62,7 +63,13 @@
return buf.toString();
}
+ public static String repeat(char character, int times) {
+ char[] buffer = new char[times];
+ Arrays.fill( buffer, character );
+ return new String( buffer );
+ }
+
public static String replace(String template, String placeholder, String replacement) {
return replace( template, placeholder, replacement, false );
}