Open Source Repository

Home /hibernate/hibernate-3.2.4.ga | Repository Home



org/hibernate/engine/query/ParameterParser.java
package org.hibernate.engine.query;

import org.hibernate.QueryException;
import org.hibernate.hql.classic.ParserHelper;
import org.hibernate.util.StringHelper;

/**
 * The single available method {@link #parse} is responsible for parsing a
 * query string and recognizing tokens in relation to parameters (either
 * named, JPA-style, or ordinal) and providing callbacks about such
 * recognitions.
 *
 @author <a href="mailto:[email protected]">Steve Ebersole </a>
 */
public class ParameterParser {

  public static interface Recognizer {
    public void outParameter(int position);
    public void ordinalParameter(int position);
    public void namedParameter(String name, int position);
    public void jpaPositionalParameter(String name, int position);
    public void other(char character);
  }

  private ParameterParser() {
    // disallow instantiation
  }

  /**
   * Performs the actual parsing and tokenizing of the query string making appropriate
   * callbacks to the given recognizer upon recognition of the various tokens.
   <p/>
   * Note that currently, this only knows how to deal with a single output
   * parameter (for callable statements).  If we later add support for
   * multiple output params, this, obviously, needs to change.
   *
   @param sqlString The string to be parsed/tokenized.
   @param recognizer The thing which handles recognition events.
   @throws QueryException
   */
  public static void parse(String sqlString, Recognizer recognizerthrows QueryException {
    boolean hasMainOutputParameter = sqlString.indexOf"call" &&
                                     sqlString.indexOf"?" < sqlString.indexOf"call" &&
                                     sqlString.indexOf"=" < sqlString.indexOf"call" );
    boolean foundMainOutputParam = false;

    int stringLength = sqlString.length();
    boolean inQuote = false;
    for int indx = 0; indx < stringLength; indx++ ) {
      char c = sqlString.charAtindx );
      if inQuote ) {
        if '\'' == c ) {
          inQuote = false;
        }
        recognizer.other);
      }
      else if '\'' == c ) {
        inQuote = true;
        recognizer.other);
      }
      else {
        if c == ':' ) {
          // named parameter
          int right = StringHelper.firstIndexOfCharsqlString, ParserHelper.HQL_SEPARATORS, indx + );
          int chopLocation = right < ? sqlString.length() : right;
          String param = sqlString.substringindx + 1, chopLocation );
          if StringHelper.isEmptyparam ) ) {
            throw new QueryException("Space is not allowed after parameter prefix ':' '"
                + sqlString + "'");
          }
          recognizer.namedParameterparam, indx );
          indx = chopLocation - 1;
        }
        else if c == '?' ) {
          // could be either an ordinal or JPA-positional parameter
          if indx < stringLength - && Character.isDigitsqlString.charAtindx + ) ) ) {
            // a peek ahead showed this as an JPA-positional parameter
            int right = StringHelper.firstIndexOfCharsqlString, ParserHelper.HQL_SEPARATORS, indx + );
            int chopLocation = right < ? sqlString.length() : right;
            String param = sqlString.substringindx + 1, chopLocation );
            // make sure this "name" is an integral
            try {
              new Integerparam );
            }
            catchNumberFormatException e ) {
              throw new QueryException"JPA-style positional param was not an integral ordinal" );
            }
            recognizer.jpaPositionalParameterparam, indx );
            indx = chopLocation - 1;
          }
          else {
            if hasMainOutputParameter && !foundMainOutputParam ) {
              foundMainOutputParam = true;
              recognizer.outParameterindx );
            }
            else {
              recognizer.ordinalParameterindx );
            }
          }
        }
        else {
          recognizer.other);
        }
      }
    }
  }

}