All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fr.ms.log4jdbc.utils.DefaultSQLFormatter Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.    
 */
package fr.ms.log4jdbc.utils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

/*
 * Lots of this could be abstracted out into a word-wrapping class.
 */

/**
 * Converts single-line SQL strings into nicely-formatted multi-line, indented statements. Example:
 *  select * from PERSON t0,
 * COMPANY t1 WHERE t0.ID = 10 AND \ t0.COMPANY_ID = t1.ID AND t1.NAME = 'OpenJPA' becomes
 * SELECT * FROM PERSON t0, COMPANY t1
 * WHERE t0.ID = 10 AND t0.COMPANY_ID = t1.ID AND t1.NAME = 'OpenJPA'\
 *  and INSERT INTO PERSON VALUES('Patrick', 'Linskey', 'OpenJPA', \
 * '202 595 2064 x1111') becomes INSERT INTO PERSON VALUES('Patrick', 'Linskey', 'OpenJPA', '202
 * 595 2064 x1111') etc.
 *
 * @author Patrick Linskey
 */
public class DefaultSQLFormatter implements SQLFormatter {

  private boolean multiLine = true;
  private boolean doubleSpace = false;
  private String newline = System.getProperty("line.separator");
  private int lineLength = 72;
  private String wrapIndent = "        ";
  private String clauseIndent = "    ";

  private static final String[] selectSeparators = new String[]{"FROM ", "WHERE ", "ORDER BY ", // ### is this order
                                                                                                // correct?
      "GROUP BY ", "HAVING ",};

  private static final String[] insertSeparators = new String[]{"VALUES ",};

  private static final String[] updateSeparators = new String[]{"SET ", "WHERE ",};

  private static final String[] deleteSeparators = new String[]{"WHERE ",};

  private static final String[] createTableSeparators = new String[]{"( ",};

  private static final String[] createIndexSeparators = new String[]{"ON ", "( ",};

  public void setNewline(final String val) {
    newline = val;
  }

  public String getNewline() {
    return newline;
  }

  public void setLineLength(final int val) {
    lineLength = val;
  }

  public int getLineLength() {
    return lineLength;
  }

  public void setWrapIndent(final String val) {
    wrapIndent = val;
  }

  public String getWrapIndent() {
    return wrapIndent;
  }

  public void setClauseIndent(final String val) {
    clauseIndent = val;
  }

  public String getClauseIndent() {
    return clauseIndent;
  }

  /**
   * If true, then try to parse multi-line SQL statements.
   * 
   * @param multiLine multiLine
   */
  public void setMultiLine(final boolean multiLine) {
    this.multiLine = multiLine;
  }

  /**
   * If true, then try to parse multi-line SQL statements.
   * 
   * @return multiLine
   */
  public boolean getMultiLine() {
    return this.multiLine;
  }

  /**
   * If true, then output two lines after multi-line statements.
   * 
   * @param doubleSpace doubleSpace
   */
  public void setDoubleSpace(final boolean doubleSpace) {
    this.doubleSpace = doubleSpace;
  }

  /**
   * If true, then output two lines after multi-line statements.
   * 
   * @return doubleSpace
   */
  public boolean getDoubleSpace() {
    return this.doubleSpace;
  }

  public String prettyPrint(final String sqlObject) {
    if (!multiLine) {
      return prettyPrintLine(sqlObject);
    } else {
      final StringBuffer sql = new StringBuffer(sqlObject);
      final StringBuffer buf = new StringBuffer(sql.length());

      while (sql.length() > 0) {
        String line = null;

        final int index = Math.max(sql.toString().indexOf(";\n"), sql.toString().indexOf(";\r"));
        if (index == -1) {
          line = sql.toString();
        } else {
          line = sql.substring(0, index + 2);
        }

        // remove the current line from the sql buffer
        sql.delete(0, line.length());

        buf.append(prettyPrintLine(line));
        for (int i = 0; i < 1 + (getDoubleSpace() ? 1 : 0); i++) {
          buf.append(System.getProperty("line.separator"));
        }
      }

      return buf.toString().trim();
    }
  }

  private String prettyPrintLine(final String sqlObject) {
    final String sql = sqlObject.trim();
    final String lowerCaseSql = sql.toLowerCase();

    String[] separators;
    if (lowerCaseSql.startsWith("select")) {
      separators = selectSeparators;
    } else if (lowerCaseSql.startsWith("insert")) {
      separators = insertSeparators;
    } else if (lowerCaseSql.startsWith("update")) {
      separators = updateSeparators;
    } else if (lowerCaseSql.startsWith("delete")) {
      separators = deleteSeparators;
    } else if (lowerCaseSql.startsWith("create table")) {
      separators = createTableSeparators;
    } else if (lowerCaseSql.startsWith("create index")) {
      separators = createIndexSeparators;
    } else {
      separators = new String[0];
    }

    int start = 0;
    int end = -1;
    StringBuffer clause;
    final List clauses = new ArrayList();
    clauses.add(new StringBuffer());

    for (int i = 0; i < separators.length; i++) {
      final String separator = separators[i];

      end = lowerCaseSql.indexOf(" " + separator.toLowerCase(), start);
      if (end == -1) {
        break;
      }

      clause = (StringBuffer) clauses.get(clauses.size() - 1);
      clause.append(sql.substring(start, end));

      clause = new StringBuffer();
      clauses.add(clause);
      clause.append(clauseIndent);
      clause.append(separator);

      start = end + 1 + separator.length();
    }

    clause = (StringBuffer) clauses.get(clauses.size() - 1);
    clause.append(sql.substring(start));

    final StringBuffer pp = new StringBuffer(sql.length());
    for (final Iterator iter = clauses.iterator(); iter.hasNext();) {
      pp.append(wrapLine(iter.next().toString()));
      if (iter.hasNext()) {
        pp.append(newline);
      }
    }

    return pp.toString();
  }

  private String wrapLine(final String line) {
    final StringBuffer lines = new StringBuffer(line.length());

    // ensure that any leading whitespace is preserved.
    for (int i = 0; i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t'); i++) {
      lines.append(line.charAt(i));
    }

    final StringTokenizer tok = new StringTokenizer(line);
    int length = 0;
    String elem;
    while (tok.hasMoreTokens()) {
      elem = tok.nextToken();
      length += elem.length();

      // if we would have exceeded the max, write out a newline
      // before writing the elem.
      if (length >= lineLength) {
        lines.append(newline);
        lines.append(wrapIndent);
        lines.append(elem);
        lines.append(' ');
        length = wrapIndent.length() + elem.length() + 1;
        continue;
      }

      // if the current length is greater than the max, then the
      // last word alone was too long, so just write out a
      // newline and move on.
      if (elem.length() >= lineLength) {
        lines.append(elem);
        if (tok.hasMoreTokens()) {
          lines.append(newline);
        }
        lines.append(wrapIndent);
        length = wrapIndent.length();
        continue;
      }

      lines.append(elem);
      lines.append(' ');
      length++;
    }

    return lines.toString();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy