Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » pretty » [javadoc | source]
    1   //$Id: Formatter.java 7815 2005-08-10 18:44:32Z oneovthafew $
    2   package org.hibernate.pretty;
    3   
    4   import java.util.HashSet;
    5   import java.util.LinkedList;
    6   import java.util.Set;
    7   import java.util.StringTokenizer;
    8   
    9   import org.hibernate.util.StringHelper;
   10   
   11   public class Formatter {
   12   	
   13   	private static final Set BEGIN_CLAUSES = new HashSet();
   14   	private static final Set END_CLAUSES = new HashSet();
   15   	private static final Set LOGICAL = new HashSet();
   16   	private static final Set QUANTIFIERS = new HashSet();
   17   	private static final Set DML = new HashSet();
   18   	private static final Set MISC = new HashSet();
   19   	static {
   20   		
   21   		BEGIN_CLAUSES.add("left");
   22   		BEGIN_CLAUSES.add("right");
   23   		BEGIN_CLAUSES.add("inner");
   24   		BEGIN_CLAUSES.add("outer");
   25   		BEGIN_CLAUSES.add("group");
   26   		BEGIN_CLAUSES.add("order");
   27   
   28   		END_CLAUSES.add("where");
   29   		END_CLAUSES.add("set");
   30   		END_CLAUSES.add("having");
   31   		END_CLAUSES.add("join");
   32   		END_CLAUSES.add("from");
   33   		END_CLAUSES.add("by");
   34   		END_CLAUSES.add("join");
   35   		END_CLAUSES.add("into");
   36   		END_CLAUSES.add("union");
   37   		
   38   		LOGICAL.add("and");
   39   		LOGICAL.add("or");
   40   		LOGICAL.add("when");
   41   		LOGICAL.add("else");
   42   		LOGICAL.add("end");
   43   		
   44   		QUANTIFIERS.add("in");
   45   		QUANTIFIERS.add("all");
   46   		QUANTIFIERS.add("exists");
   47   		QUANTIFIERS.add("some");
   48   		QUANTIFIERS.add("any");
   49   		
   50   		DML.add("insert");
   51   		DML.add("update");
   52   		DML.add("delete");
   53   		
   54   		MISC.add("select");
   55   		MISC.add("on");
   56   		//MISC.add("values");
   57   
   58   	}
   59   	
   60   	String indentString = "    ";
   61   	String initial = "\n    ";
   62   
   63   	boolean beginLine = true;
   64   	boolean afterBeginBeforeEnd = false;
   65   	boolean afterByOrSetOrFromOrSelect = false;
   66   	boolean afterValues = false;
   67   	boolean afterOn = false;
   68   	boolean afterBetween = false;
   69   	boolean afterInsert = false;
   70   	int inFunction = 0;
   71   	int parensSinceSelect = 0;
   72   	private LinkedList parenCounts = new LinkedList();
   73   	private LinkedList afterByOrFromOrSelects = new LinkedList();
   74   
   75   	int indent = 1;
   76   
   77   	StringBuffer result = new StringBuffer();
   78   	StringTokenizer tokens;
   79   	String lastToken;
   80   	String token;
   81   	String lcToken;
   82   	
   83   	public Formatter(String sql) {
   84   		tokens = new StringTokenizer(
   85   				sql, 
   86   				"()+*/-=<>'`\"[]," + StringHelper.WHITESPACE, 
   87   				true
   88   			);
   89   	}
   90   
   91   	public Formatter setInitialString(String initial) {
   92   		this.initial = initial;
   93   		return this;
   94   	}
   95   	
   96   	public Formatter setIndentString(String indent) {
   97   		this.indentString = indent;
   98   		return this;
   99   	}
  100   	
  101   	public String format() {
  102   		
  103   		result.append(initial);
  104   		
  105   		while ( tokens.hasMoreTokens() ) {
  106   			token = tokens.nextToken();
  107   			lcToken = token.toLowerCase();
  108   			
  109   			if ( "'".equals(token) ) {
  110   				String t;
  111   				do {
  112   					t = tokens.nextToken();
  113   					token += t;
  114   				} 
  115   				while ( !"'".equals(t) );
  116   			}		
  117   			else if ( "\"".equals(token) ) {
  118   				String t;
  119   				do {
  120   					t = tokens.nextToken();
  121   					token += t;
  122   				} 
  123   				while ( !"\"".equals(t) );
  124   			}
  125   			
  126   			if ( afterByOrSetOrFromOrSelect && ",".equals(token) ) {
  127   				commaAfterByOrFromOrSelect();
  128   			}
  129   			else if ( afterOn && ",".equals(token) ) {
  130   				commaAfterOn();
  131   			}
  132   			
  133   			else if ( "(".equals(token) ) {
  134   				openParen();
  135   			}
  136   			else if ( ")".equals(token) ) {
  137   				closeParen();
  138   			}
  139   
  140   			else if ( BEGIN_CLAUSES.contains(lcToken) ) {
  141   				beginNewClause();
  142   			}
  143   
  144   			else if ( END_CLAUSES.contains(lcToken) ) {
  145   				endNewClause(); 
  146   			}
  147   			
  148   			else if ( "select".equals(lcToken) ) {
  149   				select();
  150   			}
  151   			
  152   			else if ( DML.contains(lcToken) ) {
  153   				updateOrInsertOrDelete();
  154   			}
  155   			
  156   			else if ( "values".equals(lcToken) ) {
  157   				values();
  158   			}
  159   			
  160   			else if ( "on".equals(lcToken) ) {
  161   				on();
  162   			}
  163   			
  164   			else if ( afterBetween && lcToken.equals("and") ) {
  165   				misc();
  166   				afterBetween = false;
  167   			}
  168   			
  169   			else if ( LOGICAL.contains(lcToken) ) {
  170   				logical();
  171   			}
  172   			
  173   			else if ( isWhitespace(token) ) {
  174   				white();
  175   			}
  176   			
  177   			else {
  178   				misc();
  179   			}
  180   			
  181   			if ( !isWhitespace( token ) ) lastToken = lcToken;
  182   			
  183   		}
  184   		return result.toString();
  185   	}
  186   
  187   	private void commaAfterOn() {
  188   		out();
  189   		indent--;
  190   		newline();
  191   		afterOn = false;
  192   		afterByOrSetOrFromOrSelect = true;
  193   	}
  194   
  195   	private void commaAfterByOrFromOrSelect() {
  196   		out();
  197   		newline();
  198   	}
  199   
  200   	private void logical() {
  201   		if ( "end".equals(lcToken) ) indent--;
  202   		newline();
  203   		out();
  204   		beginLine = false;
  205   	}
  206   
  207   	private void on() {
  208   		indent++;
  209   		afterOn = true;
  210   		newline();
  211   		out();
  212   		beginLine = false;
  213   	}
  214   
  215   	private void misc() {
  216   		out();
  217   		if ( "between".equals(lcToken) ) {
  218   			afterBetween = true;
  219   		}
  220   		if (afterInsert) {
  221   			newline();
  222   			afterInsert = false;
  223   		}
  224   		else {
  225   			beginLine = false;
  226   			if ( "case".equals(lcToken) ) {
  227   				indent++;
  228   			}
  229   		}
  230   	}
  231   
  232   	private void white() {
  233   		if ( !beginLine ) {
  234   			result.append(" ");
  235   		}
  236   	}
  237   	
  238   	private void updateOrInsertOrDelete() {
  239   		out();
  240   		indent++;
  241   		beginLine = false;
  242   		if ( "update".equals(lcToken) ) newline();
  243   		if ( "insert".equals(lcToken) ) afterInsert = true;
  244   	}
  245   
  246   	private void select() {
  247   		out();
  248   		indent++;
  249   		newline();
  250   		parenCounts.addLast( new Integer(parensSinceSelect) );
  251   		afterByOrFromOrSelects.addLast( new Boolean(afterByOrSetOrFromOrSelect) );
  252   		parensSinceSelect = 0;
  253   		afterByOrSetOrFromOrSelect = true;
  254   	}
  255   
  256   	private void out() {
  257   		result.append(token);
  258   	}
  259   
  260   	private void endNewClause() {
  261   		if (!afterBeginBeforeEnd) {
  262   			indent--;
  263   			if (afterOn) {
  264   				indent--;
  265   				afterOn=false;
  266   			}
  267   			newline();
  268   		}
  269   		out();
  270   		if ( !"union".equals(lcToken) ) indent++;
  271   		newline();
  272   		afterBeginBeforeEnd = false;
  273   		afterByOrSetOrFromOrSelect = "by".equals(lcToken) 
  274   				|| "set".equals(lcToken)
  275   				|| "from".equals(lcToken);
  276   	}
  277   
  278   	private void beginNewClause() {
  279   		if (!afterBeginBeforeEnd) {
  280   			if (afterOn) {
  281   				indent--;
  282   				afterOn=false;
  283   			}
  284   			indent--;
  285   			newline();
  286   		}
  287   		out();
  288   		beginLine = false;
  289   		afterBeginBeforeEnd = true;
  290   	}
  291   
  292   	private void values() {
  293   		indent--;
  294   		newline();
  295   		out();
  296   		indent++;
  297   		newline();
  298   		afterValues = true;
  299   	}
  300   
  301   	private void closeParen() {
  302   		parensSinceSelect--;
  303   		if (parensSinceSelect<0) {
  304   			indent--;
  305   			parensSinceSelect = ( (Integer) parenCounts.removeLast() ).intValue();
  306   			afterByOrSetOrFromOrSelect = ( (Boolean) afterByOrFromOrSelects.removeLast() ).booleanValue();
  307   		}
  308   		if ( inFunction>0 ) {
  309   			inFunction--;
  310   			out();
  311   		}
  312   		else {
  313   			if (!afterByOrSetOrFromOrSelect) {
  314   				indent--;
  315   				newline();
  316   			}
  317   			out();
  318   		}
  319   		beginLine = false;
  320   	}
  321   
  322   	private void openParen() {
  323   		if ( isFunctionName( lastToken ) || inFunction>0 ) {
  324   			inFunction++;
  325   		}
  326   		beginLine = false;
  327   		if ( inFunction>0 ) {
  328   			out();
  329   		}
  330   		else {
  331   			out();
  332   			if (!afterByOrSetOrFromOrSelect) {
  333   				indent++;
  334   				newline();
  335   				beginLine = true;
  336   			}
  337   		}
  338   		parensSinceSelect++;
  339   	}
  340   
  341   	private static boolean isFunctionName(String tok) {
  342   		final char begin = tok.charAt(0);
  343   		final boolean isIdentifier = Character.isJavaIdentifierStart( begin ) || '"'==begin;
  344   		return isIdentifier && 
  345   				!LOGICAL.contains(tok) && 
  346   				!END_CLAUSES.contains(tok) &&
  347   				!QUANTIFIERS.contains(tok) &&
  348   				!DML.contains(tok) &&
  349   				!MISC.contains(tok);
  350   	}
  351   
  352   	private static boolean isWhitespace(String token) {
  353   		return StringHelper.WHITESPACE.indexOf(token)>=0;
  354   	}
  355   	
  356   	private void newline() {
  357   		result.append("\n");
  358   		for ( int i=0; i<indent; i++ ) {
  359   			result.append(indentString);
  360   		}
  361   		beginLine = true;
  362   	}
  363   
  364   	public static void main(String[] args) {
  365   		if ( args.length>0 ) System.out.println( 
  366   			new Formatter( StringHelper.join(" ", args) ).format()
  367   		);
  368   		System.out.println( 
  369   			new Formatter("insert into Address (city, state, zip, \"from\") values (?, ?, ?, 'insert value')").format()
  370   		);
  371   		System.out.println( 
  372   			new Formatter("delete from Address where id = ? and version = ?").format()
  373   		);
  374   		System.out.println( 
  375   			new Formatter("update Address set city = ?, state=?, zip=?, version = ? where id = ? and version = ?").format()
  376   		);
  377   		System.out.println( 
  378   			new Formatter("update Address set city = ?, state=?, zip=?, version = ? where id in (select aid from Person)").format()
  379   		);
  380   		System.out.println( 
  381   			new Formatter("select p.name, a.zipCode, count(*) from Person p left outer join Employee e on e.id = p.id and p.type = 'E' and (e.effective>? or e.effective<?) join Address a on a.pid = p.id where upper(p.name) like 'G%' and p.age > 100 and (p.sex = 'M' or p.sex = 'F') and coalesce( trim(a.street), a.city, (a.zip) ) is not null order by p.name asc, a.zipCode asc").format()
  382   		);
  383   		System.out.println( 
  384   			new Formatter("select ( (m.age - p.age) * 12 ), trim(upper(p.name)) from Person p, Person m where p.mother = m.id and ( p.age = (select max(p0.age) from Person p0 where (p0.mother=m.id)) and p.name like ? )").format()
  385   		);
  386   		System.out.println( 
  387   			new Formatter("select * from Address a join Person p on a.pid = p.id, Person m join Address b on b.pid = m.id where p.mother = m.id and p.name like ?").format()
  388   		);
  389   		System.out.println( 
  390   			new Formatter("select case when p.age > 50 then 'old' when p.age > 18 then 'adult' else 'child' end from Person p where ( case when p.age > 50 then 'old' when p.age > 18 then 'adult' else 'child' end ) like ?").format()
  391   		);
  392   	}
  393   
  394   }

Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » pretty » [javadoc | source]