/*
 * 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;
import java.util.HashSet;
import java.util.Iterator;

import org.hibernate.dialect.Dialect;

A translated HQL query
Author:Gavin King
/** * A translated HQL query * @author Gavin King */
public class QuerySelect { private Dialect dialect; private JoinFragment joins; private StringBuilder select = new StringBuilder(); private StringBuilder where = new StringBuilder(); private StringBuilder groupBy = new StringBuilder(); private StringBuilder orderBy = new StringBuilder(); private StringBuilder having = new StringBuilder(); private String comment; private boolean distinct; private static final HashSet DONT_SPACE_TOKENS = new HashSet(); static { //dontSpace.add("'"); DONT_SPACE_TOKENS.add("."); DONT_SPACE_TOKENS.add("+"); DONT_SPACE_TOKENS.add("-"); DONT_SPACE_TOKENS.add("/"); DONT_SPACE_TOKENS.add("*"); DONT_SPACE_TOKENS.add("<"); DONT_SPACE_TOKENS.add(">"); DONT_SPACE_TOKENS.add("="); DONT_SPACE_TOKENS.add("#"); DONT_SPACE_TOKENS.add("~"); DONT_SPACE_TOKENS.add("|"); DONT_SPACE_TOKENS.add("&"); DONT_SPACE_TOKENS.add("<="); DONT_SPACE_TOKENS.add(">="); DONT_SPACE_TOKENS.add("=>"); DONT_SPACE_TOKENS.add("=<"); DONT_SPACE_TOKENS.add("!="); DONT_SPACE_TOKENS.add("<>"); DONT_SPACE_TOKENS.add("!#"); DONT_SPACE_TOKENS.add("!~"); DONT_SPACE_TOKENS.add("!<"); DONT_SPACE_TOKENS.add("!>"); DONT_SPACE_TOKENS.add("("); //for MySQL DONT_SPACE_TOKENS.add(")"); } public QuerySelect(Dialect dialect) { this.dialect = dialect; joins = new QueryJoinFragment(dialect, false); } public JoinFragment getJoinFragment() { return joins; } public void addSelectFragmentString(String fragment) { if ( fragment.length()>0 && fragment.charAt(0)==',' ) fragment = fragment.substring(1); fragment = fragment.trim(); if ( fragment.length()>0 ) { if ( select.length()>0 ) select.append(", "); select.append(fragment); } } public void addSelectColumn(String columnName, String alias) { addSelectFragmentString(columnName + ' ' + alias); } public void setDistinct(boolean distinct) { this.distinct = distinct; } public void setWhereTokens(Iterator tokens) { //if ( conjunctiveWhere.length()>0 ) conjunctiveWhere.append(" and "); appendTokens(where, tokens); } public void prependWhereConditions(String conditions) { if (where.length() > 0) { where.insert(0, conditions + " and "); } else { where.append(conditions); } } public void setGroupByTokens(Iterator tokens) { //if ( groupBy.length()>0 ) groupBy.append(" and "); appendTokens(groupBy, tokens); } public void setOrderByTokens(Iterator tokens) { //if ( orderBy.length()>0 ) orderBy.append(" and "); appendTokens(orderBy, tokens); } public void setHavingTokens(Iterator tokens) { //if ( having.length()>0 ) having.append(" and "); appendTokens(having, tokens); } public void addOrderBy(String orderByString) { if ( orderBy.length() > 0 ) orderBy.append(", "); orderBy.append(orderByString); } public String toQueryString() { StringBuilder buf = new StringBuilder(50); if (comment!=null) buf.append("/* ").append(comment).append(" */ "); buf.append("select "); if (distinct) buf.append("distinct "); String from = joins.toFromFragmentString(); if ( from.startsWith(",") ) { from = from.substring(1); } else if ( from.startsWith(" inner join") ){ from = from.substring(11); } buf.append( select.toString() ) .append(" from") .append(from); String outerJoinsAfterWhere = joins.toWhereFragmentString().trim(); String whereConditions = where.toString().trim(); boolean hasOuterJoinsAfterWhere = outerJoinsAfterWhere.length() > 0; boolean hasWhereConditions = whereConditions.length() > 0; if (hasOuterJoinsAfterWhere || hasWhereConditions) { buf.append(" where "); if (hasOuterJoinsAfterWhere) { buf.append( outerJoinsAfterWhere.substring(4) ); } if (hasWhereConditions) { if (hasOuterJoinsAfterWhere) { buf.append(" and ("); } buf.append(whereConditions); if (hasOuterJoinsAfterWhere) { buf.append(")"); } } } if ( groupBy.length() > 0 ) buf.append(" group by ").append( groupBy.toString() ); if ( having.length() > 0 ) buf.append(" having ").append( having.toString() ); if ( orderBy.length() > 0 ) buf.append(" order by ").append( orderBy.toString() ); return dialect.transformSelectString( buf.toString() ); } private static void appendTokens(StringBuilder buf, Iterator iter) { boolean lastSpaceable=true; boolean lastQuoted=false; while ( iter.hasNext() ) { String token = (String) iter.next(); boolean spaceable = !DONT_SPACE_TOKENS.contains(token); boolean quoted = token.startsWith("'"); if (spaceable && lastSpaceable) { if ( !quoted || !lastQuoted ) buf.append(' '); } lastSpaceable = spaceable; buf.append(token); lastQuoted = token.endsWith("'"); } } public void setComment(String comment) { this.comment = comment; } public QuerySelect copy() { QuerySelect copy = new QuerySelect(dialect); copy.joins = this.joins.copy(); copy.select.append( this.select.toString() ); copy.where.append( this.where.toString() ); copy.groupBy.append( this.groupBy.toString() ); copy.orderBy.append( this.orderBy.toString() ); copy.having.append( this.having.toString() ); copy.comment = this.comment; copy.distinct = this.distinct; return copy; } }