~raginggoblin/infolog/infolog

« back to all changes in this revision

Viewing changes to InfologServer/lib/hibernate-distribution-3.3.2.GA/project/core/src/main/java/org/hibernate/hql/ast/util/JoinProcessor.java

  • Committer: Raging Goblin
  • Date: 2013-11-16 16:51:32 UTC
  • Revision ID: raging_goblin-20131116165132-weujnptzc88uy4ah
Mavenized the project, now using shared project InfologSync

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Hibernate, Relational Persistence for Idiomatic Java
3
 
 *
4
 
 * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
5
 
 * indicated by the @author tags or express copyright attribution
6
 
 * statements applied by the authors.  All third-party contributions are
7
 
 * distributed under license by Red Hat Middleware LLC.
8
 
 *
9
 
 * This copyrighted material is made available to anyone wishing to use, modify,
10
 
 * copy, or redistribute it subject to the terms and conditions of the GNU
11
 
 * Lesser General Public License, as published by the Free Software Foundation.
12
 
 *
13
 
 * This program is distributed in the hope that it will be useful,
14
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15
 
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
16
 
 * for more details.
17
 
 *
18
 
 * You should have received a copy of the GNU Lesser General Public License
19
 
 * along with this distribution; if not, write to:
20
 
 * Free Software Foundation, Inc.
21
 
 * 51 Franklin Street, Fifth Floor
22
 
 * Boston, MA  02110-1301  USA
23
 
 *
24
 
 */
25
 
package org.hibernate.hql.ast.util;
26
 
 
27
 
import java.util.ArrayList;
28
 
import java.util.Iterator;
29
 
import java.util.ListIterator;
30
 
import java.util.List;
31
 
import java.util.StringTokenizer;
32
 
import java.util.Collection;
33
 
 
34
 
import org.hibernate.AssertionFailure;
35
 
import org.hibernate.dialect.Dialect;
36
 
import org.hibernate.impl.FilterImpl;
37
 
import org.hibernate.type.Type;
38
 
import org.hibernate.param.DynamicFilterParameterSpecification;
39
 
import org.hibernate.engine.JoinSequence;
40
 
import org.hibernate.engine.QueryParameters;
41
 
import org.hibernate.hql.antlr.SqlTokenTypes;
42
 
import org.hibernate.hql.ast.HqlSqlWalker;
43
 
import org.hibernate.hql.ast.tree.FromClause;
44
 
import org.hibernate.hql.ast.tree.FromElement;
45
 
import org.hibernate.hql.ast.tree.QueryNode;
46
 
import org.hibernate.hql.ast.tree.DotNode;
47
 
import org.hibernate.hql.ast.tree.ParameterContainer;
48
 
import org.hibernate.hql.classic.ParserHelper;
49
 
import org.hibernate.sql.JoinFragment;
50
 
import org.hibernate.util.StringHelper;
51
 
import org.hibernate.util.ArrayHelper;
52
 
 
53
 
import org.slf4j.Logger;
54
 
import org.slf4j.LoggerFactory;
55
 
 
56
 
/**
57
 
 * Performs the post-processing of the join information gathered during semantic analysis.
58
 
 * The join generating classes are complex, this encapsulates some of the JoinSequence-related
59
 
 * code.
60
 
 *
61
 
 * @author Joshua Davis
62
 
 */
63
 
public class JoinProcessor implements SqlTokenTypes {
64
 
 
65
 
        private static final Logger log = LoggerFactory.getLogger( JoinProcessor.class );
66
 
 
67
 
        private final HqlSqlWalker walker;
68
 
        private final SyntheticAndFactory syntheticAndFactory;
69
 
 
70
 
        /**
71
 
         * Constructs a new JoinProcessor.
72
 
         *
73
 
         * @param walker The walker to which we are bound, giving us access to needed resources.
74
 
         */
75
 
        public JoinProcessor(HqlSqlWalker walker) {
76
 
                this.walker = walker;
77
 
                this.syntheticAndFactory = new SyntheticAndFactory( walker );
78
 
        }
79
 
 
80
 
        /**
81
 
         * Translates an AST join type (i.e., the token type) into a JoinFragment.XXX join type.
82
 
         *
83
 
         * @param astJoinType The AST join type (from HqlSqlTokenTypes or SqlTokenTypes)
84
 
         * @return a JoinFragment.XXX join type.
85
 
         * @see JoinFragment
86
 
         * @see SqlTokenTypes
87
 
         */
88
 
        public static int toHibernateJoinType(int astJoinType) {
89
 
                switch ( astJoinType ) {
90
 
                        case LEFT_OUTER:
91
 
                                return JoinFragment.LEFT_OUTER_JOIN;
92
 
                        case INNER:
93
 
                                return JoinFragment.INNER_JOIN;
94
 
                        case RIGHT_OUTER:
95
 
                                return JoinFragment.RIGHT_OUTER_JOIN;
96
 
                        default:
97
 
                                throw new AssertionFailure( "undefined join type " + astJoinType );
98
 
                }
99
 
        }
100
 
 
101
 
        public void processJoins(QueryNode query) {
102
 
                final FromClause fromClause = query.getFromClause();
103
 
 
104
 
                final List fromElements;
105
 
                if ( DotNode.useThetaStyleImplicitJoins ) {
106
 
                        // for regression testing against output from the old parser...
107
 
                        // found it easiest to simply reorder the FromElements here into ascending order
108
 
                        // in terms of injecting them into the resulting sql ast in orders relative to those
109
 
                        // expected by the old parser; this is definitely another of those "only needed
110
 
                        // for regression purposes".  The SyntheticAndFactory, then, simply injects them as it
111
 
                        // encounters them.
112
 
                        fromElements = new ArrayList();
113
 
                        ListIterator liter = fromClause.getFromElements().listIterator( fromClause.getFromElements().size() );
114
 
                        while ( liter.hasPrevious() ) {
115
 
                                fromElements.add( liter.previous() );
116
 
                        }
117
 
                }
118
 
                else {
119
 
                        fromElements = fromClause.getFromElements();
120
 
                }
121
 
 
122
 
                // Iterate through the alias,JoinSequence pairs and generate SQL token nodes.
123
 
                Iterator iter = fromElements.iterator();
124
 
                while ( iter.hasNext() ) {
125
 
                        final FromElement fromElement = ( FromElement ) iter.next();
126
 
                        JoinSequence join = fromElement.getJoinSequence();
127
 
                        join.setSelector(
128
 
                                        new JoinSequence.Selector() {
129
 
                                                public boolean includeSubclasses(String alias) {
130
 
                                                        // The uber-rule here is that we need to include  subclass joins if
131
 
                                                        // the FromElement is in any way dereferenced by a property from
132
 
                                                        // the subclass table; otherwise we end up with column references
133
 
                                                        // qualified by a non-existent table reference in the resulting SQL...
134
 
                                                        boolean containsTableAlias = fromClause.containsTableAlias( alias );
135
 
                                                        if ( fromElement.isDereferencedBySubclassProperty() ) {
136
 
                                                                // TODO : or should we return 'containsTableAlias'??
137
 
                                                                log.trace( "forcing inclusion of extra joins [alias=" + alias + ", containsTableAlias=" + containsTableAlias + "]" );
138
 
                                                                return true;
139
 
                                                        }
140
 
                                                        boolean shallowQuery = walker.isShallowQuery();
141
 
                                                        boolean includeSubclasses = fromElement.isIncludeSubclasses();
142
 
                                                        boolean subQuery = fromClause.isSubQuery();
143
 
                                                        return includeSubclasses && containsTableAlias && !subQuery && !shallowQuery;
144
 
                                                }
145
 
                                        }
146
 
                        );
147
 
                        addJoinNodes( query, join, fromElement );
148
 
                }
149
 
 
150
 
        }
151
 
 
152
 
        private void addJoinNodes(QueryNode query, JoinSequence join, FromElement fromElement) {
153
 
                JoinFragment joinFragment = join.toJoinFragment(
154
 
                                walker.getEnabledFilters(),
155
 
                                fromElement.useFromFragment() || fromElement.isDereferencedBySuperclassOrSubclassProperty(),
156
 
                                fromElement.getWithClauseFragment(),
157
 
                                fromElement.getWithClauseJoinAlias()
158
 
                );
159
 
 
160
 
                String frag = joinFragment.toFromFragmentString();
161
 
                String whereFrag = joinFragment.toWhereFragmentString();
162
 
 
163
 
                // If the from element represents a JOIN_FRAGMENT and it is
164
 
                // a theta-style join, convert its type from JOIN_FRAGMENT
165
 
                // to FROM_FRAGMENT
166
 
                if ( fromElement.getType() == JOIN_FRAGMENT &&
167
 
                                ( join.isThetaStyle() || StringHelper.isNotEmpty( whereFrag ) ) ) {
168
 
                        fromElement.setType( FROM_FRAGMENT );
169
 
                        fromElement.getJoinSequence().setUseThetaStyle( true ); // this is used during SqlGenerator processing
170
 
                }
171
 
 
172
 
                // If there is a FROM fragment and the FROM element is an explicit, then add the from part.
173
 
                if ( fromElement.useFromFragment() /*&& StringHelper.isNotEmpty( frag )*/ ) {
174
 
                        String fromFragment = processFromFragment( frag, join ).trim();
175
 
                        if ( log.isDebugEnabled() ) {
176
 
                                log.debug( "Using FROM fragment [" + fromFragment + "]" );
177
 
                        }
178
 
                        processDynamicFilterParameters(
179
 
                                        fromFragment,
180
 
                                        fromElement,
181
 
                                        walker
182
 
                        );
183
 
                }
184
 
 
185
 
                syntheticAndFactory.addWhereFragment( 
186
 
                                joinFragment,
187
 
                                whereFrag,
188
 
                                query,
189
 
                                fromElement,
190
 
                                walker
191
 
                );
192
 
        }
193
 
 
194
 
        private String processFromFragment(String frag, JoinSequence join) {
195
 
                String fromFragment = frag.trim();
196
 
                // The FROM fragment will probably begin with ', '.  Remove this if it is present.
197
 
                if ( fromFragment.startsWith( ", " ) ) {
198
 
                        fromFragment = fromFragment.substring( 2 );
199
 
                }
200
 
                return fromFragment;
201
 
        }
202
 
 
203
 
        public static void processDynamicFilterParameters(
204
 
                        final String sqlFragment,
205
 
                        final ParameterContainer container,
206
 
                        final HqlSqlWalker walker) {
207
 
                if ( walker.getEnabledFilters().isEmpty()
208
 
                                && ( ! hasDynamicFilterParam( sqlFragment ) )
209
 
                                && ( ! ( hasCollectionFilterParam( sqlFragment ) ) ) ) {
210
 
                        return;
211
 
                }
212
 
 
213
 
                Dialect dialect = walker.getSessionFactoryHelper().getFactory().getDialect();
214
 
                String symbols = new StringBuffer().append( ParserHelper.HQL_SEPARATORS )
215
 
                                .append( dialect.openQuote() )
216
 
                                .append( dialect.closeQuote() )
217
 
                                .toString();
218
 
                StringTokenizer tokens = new StringTokenizer( sqlFragment, symbols, true );
219
 
                StringBuffer result = new StringBuffer();
220
 
 
221
 
                while ( tokens.hasMoreTokens() ) {
222
 
                        final String token = tokens.nextToken();
223
 
                        if ( token.startsWith( ParserHelper.HQL_VARIABLE_PREFIX ) ) {
224
 
                                final String filterParameterName = token.substring( 1 );
225
 
                                final String[] parts = QueryParameters.parseFilterParameterName( filterParameterName );
226
 
                                final FilterImpl filter = ( FilterImpl ) walker.getEnabledFilters().get( parts[0] );
227
 
                                final Object value = filter.getParameter( parts[1] );
228
 
                                final Type type = filter.getFilterDefinition().getParameterType( parts[1] );
229
 
                                final String typeBindFragment = StringHelper.join(
230
 
                                                ",",
231
 
                                                ArrayHelper.fillArray( "?", type.getColumnSpan( walker.getSessionFactoryHelper().getFactory() ) )
232
 
                                );
233
 
                                final String bindFragment = ( value != null && Collection.class.isInstance( value ) )
234
 
                                                ? StringHelper.join( ",", ArrayHelper.fillArray( typeBindFragment, ( ( Collection ) value ).size() ) )
235
 
                                                : typeBindFragment;
236
 
                                result.append( bindFragment );
237
 
                                container.addEmbeddedParameter( new DynamicFilterParameterSpecification( parts[0], parts[1], type ) );
238
 
                        }
239
 
                        else {
240
 
                                result.append( token );
241
 
                        }
242
 
                }
243
 
 
244
 
                container.setText( result.toString() );
245
 
        }
246
 
 
247
 
        private static boolean hasDynamicFilterParam(String sqlFragment) {
248
 
                return sqlFragment.indexOf( ParserHelper.HQL_VARIABLE_PREFIX ) < 0;
249
 
        }
250
 
 
251
 
        private static boolean hasCollectionFilterParam(String sqlFragment) {
252
 
                return sqlFragment.indexOf( "?" ) < 0;
253
 
        }
254
 
 
255
 
}