Package net.sourceforge.squirrel_sql.plugins.netezza.tokenizer

Source Code of net.sourceforge.squirrel_sql.plugins.netezza.tokenizer.NetezzaQueryTokenizer

package net.sourceforge.squirrel_sql.plugins.netezza.tokenizer;

/*
* Copyright (C) 2007 Rob Manning
* manningr@users.sourceforge.net
*
* Based on initial work from Johan Compagner.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
import java.util.ArrayList;
import java.util.Iterator;
import java.util.regex.Pattern;

import net.sourceforge.squirrel_sql.fw.preferences.IQueryTokenizerPreferenceBean;
import net.sourceforge.squirrel_sql.fw.sql.IQueryTokenizer;
import net.sourceforge.squirrel_sql.fw.sql.ITokenizerFactory;
import net.sourceforge.squirrel_sql.fw.sql.QueryTokenizer;
import net.sourceforge.squirrel_sql.fw.sql.TokenizerSessPropsInteractions;
import net.sourceforge.squirrel_sql.fw.util.StringUtilities;
import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;

/**
* This class is loaded by the Netezza Plugin and registered with all Netezza Sessions as the query tokenizer
* if the plugin is loaded. It handles some of the syntax allowed in Netezza scripts that would be hard to
* parse in a generic way for any database. It handles create statements for stored procedures.
*/
public class NetezzaQueryTokenizer extends QueryTokenizer implements IQueryTokenizer
{
  /** Logger for this class. */
  private final static ILogger s_log = LoggerController.createLogger(NetezzaQueryTokenizer.class);

  private static final String PROCEDURE_PATTERN =
    "^\\s*CREATE\\s+PROCEDURE.*|^\\s*CREATE\\s+OR\\s+REPLACE\\s+PROCEDURE\\s+.*";

  private Pattern procPattern = Pattern.compile(PROCEDURE_PATTERN, Pattern.DOTALL);

  private IQueryTokenizerPreferenceBean _prefs = null;

  public NetezzaQueryTokenizer(IQueryTokenizerPreferenceBean prefs)
  {
    super(prefs.getStatementSeparator(), prefs.getLineComment(), prefs.isRemoveMultiLineComments());
    _prefs = prefs;
  }

  public void setScriptToTokenize(String script)
  {
    super.setScriptToTokenize(script);

    // Since it is likely to have the procedure separator on it's own line,
    // and it is key to letting us know that proceeding statements form a
    // multi-statement procedure or function, it deserves it's own place in
    // the _queries arraylist. If it is followed by other procedure or
    // function creation blocks, we may fail to detect that, so this just
    // goes through the list and breaks apart statements on newline so that
    // this cannot happen.
    breakApartNewLines();

    // Netezza allows statement separators in procedure blocks. The process
    // of tokenizing above renders these procedure blocks as separate
    // statements, which are not valid to be executed separately. Here, we
    // re-assemble any create procedure statements that we
    // find using the beginning procedure block pattern and the procedure
    // separator.
    joinFragments(procPattern, false);

    _queryIterator = _queries.iterator();
  }

  /**
   * Sets the ITokenizerFactory which is used to create additional instances of the IQueryTokenizer - this is
   * used for handling file includes recursively.
   */
  protected void setFactory()
  {
    _tokenizerFactory = new ITokenizerFactory()
    {
      public IQueryTokenizer getTokenizer()
      {
        return new NetezzaQueryTokenizer(_prefs);
      }
    };
  }

  /**
   * This will loop through _queries and break apart lines that look like <code>
   *
   * list:
   *   element: <sep>\n\ncreate proc...
   *   
   * into
   *
   * list:
   *   element: <sep>
   *   element: create proc...
   *
   * </code>
   */
  private void breakApartNewLines()
  {
    ArrayList<String> tmp = new ArrayList<String>();
    String procSep = _prefs.getProcedureSeparator();
    for (Iterator<String> iter = _queries.iterator(); iter.hasNext();)
    {
      String next = iter.next();
      if (next.startsWith(procSep))
      {
        tmp.add(procSep);
        String[] parts = next.split(procSep + "\\n+");
        for (int i = 0; i < parts.length; i++)
        {
          if (!"".equals(parts[i]) && !procSep.equals(parts[i]))
          {
            tmp.add(parts[i]);
          }
        }
      }
      else if (next.endsWith(procSep))
      {
        String chopped = StringUtilities.chop(next);
        tmp.add(chopped);
        tmp.add(procSep);
      }
      else
      {
        tmp.add(next);
      }
    }
    _queries = tmp;
  }

  /**
   * This will scan the _queries list looking for fragments matching the specified pattern and will combine
   * successive fragments until the procedure separator is encountered which indicated the end of the code
   * block.
   *
   * @param skipStraySep
   *           if we find a slash before matching a pattern and this is true, we will exclude it from our
   *           list of sql queries.
   */
  private void joinFragments(Pattern pattern, boolean skipStraySep)
  {

    boolean inMultiSQLStatement = false;
    StringBuffer collector = null;
    ArrayList<String> tmp = new ArrayList<String>();
    String procSep = _prefs.getProcedureSeparator();
    String stmtSep = _prefs.getStatementSeparator();
    for (Iterator<String> iter = _queries.iterator(); iter.hasNext();)
    {
      String next = iter.next();
      if (pattern.matcher(next.toUpperCase()).matches())
      {
        inMultiSQLStatement = true;
        collector = new StringBuffer(next);
        collector.append(stmtSep);
        continue;
      }
      if (next.startsWith(procSep))
      {
        inMultiSQLStatement = false;
        if (collector != null)
        {
          // For Netezza, the procedure and statement separator must be appended - they are part of the
          // statement.
          collector.append(procSep);
          collector.append(stmtSep);
          tmp.add(collector.toString());
          collector = null;
        }
        else
        {
          if (skipStraySep)
          {
            // Stray sep - or we failed to find pattern
            if (s_log.isDebugEnabled())
            {
              s_log.debug("Detected stray procedure separator(" + procSep + "). Skipping");
            }
          }
          else
          {
            tmp.add(next);
          }
        }
        continue;
      }
      if (inMultiSQLStatement)
      {
        collector.append(next);
        collector.append(stmtSep);
        continue;
      }
      tmp.add(next);
    }
    _queries = tmp;
  }

  @Override
  public TokenizerSessPropsInteractions getTokenizerSessPropsInteractions()
  {
    if (_prefs.isInstallCustomQueryTokenizer())
    {
      TokenizerSessPropsInteractions ret = new TokenizerSessPropsInteractions();
      ret.setTokenizerDefinesRemoveMultiLineComment(true);
      ret.setTokenizerDefinesStartOfLineComment(true);
      ret.setTokenizerDefinesStatementSeparator(true);

      return ret;
    }
    else
    {
      return super.getTokenizerSessPropsInteractions();
    }
  }

}
TOP

Related Classes of net.sourceforge.squirrel_sql.plugins.netezza.tokenizer.NetezzaQueryTokenizer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.