Update of /cvsroot/squirrel-sql/sql12/app/src/net/sourceforge/squirrel_sql/client/session/parser/kernel
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31947/app/src/net/sourceforge/squirrel_sql/client/session/parser/kernel
Added Files:
Completion.java ErrorInfo.java ErrorStream.java Parser.java
ParserListener.java ParserLogger.java ParserThread.java
ParsingFinishedListener.java RestartInfo.java
SQLCompletion.java SQLSchema.java Scanner.java
TableAliasInfo.java
Log Message:
Gerd Wagners patch - adds SQL parser
--- NEW FILE: ParserThread.java ---
/*
* Copyright (C) 2002 Christian Sell
* cs...@us...
*
* 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
*
* created by cse, 07.10.2002 11:57:54
*
* @version $Id: ParserThread.java,v 1.1 2004/04/04 10:36:31 colbell Exp $
*/
package net.sourceforge.squirrel_sql.client.session.parser.kernel;
import net.sourceforge.squirrel_sql.client.session.parser.kernel.completions.ErrorListener;
import net.sourceforge.squirrel_sql.client.session.parser.kernel.completions.SQLSelectStatementListener;
import net.sourceforge.squirrel_sql.client.session.parser.kernel.completions.SQLStatement;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.Vector;
/**
* a thread subclass which drives the SQL parser. The thread reads from a _workingBuffer
* which always blocks until data is made available. It can thus be run in the
* background, parsing the input from the text UI as it arrives.
*
* <em>Unfortunately, it depends on the generated parser/scanner and therefore
* cannot be generalized, unless the generated classes are made to implement public
* interfaces</em>
*/
public class ParserThread extends Thread
{
public static final String PARSER_THREAD_NM = "SQLParserThread";
private String _pendingString;
private Errors _errors;
private SQLSchema _schema;
private SQLStatement _curSQLSelectStat;
private Vector _workingTableAliasInfos = new Vector();
private TableAliasInfo[] _lastRunTableAliasInfos = new TableAliasInfo[0];
private Vector _workingErrorInfos = new Vector();
private ErrorInfo[] _lastRunErrorInfos = new ErrorInfo[0];
private boolean _exitThread;
private ParsingFinishedListener _parsingFinishedListener;
private int _lastParserRunOffset;
private int _lastErrEnd = -1;
private int _nextStatBegin = -1;
private String _workingString;
private IncrementalBuffer _workingBuffer;
private boolean _errorDetected;
public ParserThread(SQLSchema schema)
{
super(PARSER_THREAD_NM);
this._schema = schema;
ErrorListener errListener = new ErrorListener()
{
public void errorDetected(String message, int line, int column)
{
onErrorDetected(message, line, column);
}
};
this._errors = new Errors(errListener);
start();
}
private void onErrorDetected(String message, int line, int column)
{
_errorDetected = true;
int errPos = getPos(line, column);
_lastErrEnd = getTokenEnd(errPos);
_nextStatBegin = perdicNexttStatementBegin(errPos);
_workingErrorInfos.add(new ErrorInfo(message, _lastParserRunOffset + errPos, _lastParserRunOffset + _lastErrEnd));
}
private int perdicNexttStatementBegin(int errPos)
{
int ret = errPos;
while( _workingString.length() > ret && false == startsWithBeginKeyWord(ret) )
{
++ret;
}
return ret;
}
private boolean startsWithBeginKeyWord(int ret)
{
return startsWithIgnoreCase(ret, "SELECT")
|| startsWithIgnoreCase(ret, "UPDATE")
|| startsWithIgnoreCase(ret, "DELETE")
|| startsWithIgnoreCase(ret, "INSERT")
|| startsWithIgnoreCase(ret, "ALTER")
|| startsWithIgnoreCase(ret, "CREATE")
|| startsWithIgnoreCase(ret, "DROP");
}
private boolean startsWithIgnoreCase(int ret, String keyWord)
{
int beginPos;
int endPos;
if(ret == 0)
{
beginPos = 0;
}
else if(Character.isWhitespace(_workingString.charAt(ret)))
{
beginPos = ret + 1;
}
else
{
return false;
}
if(_workingString.length() == beginPos + keyWord.length())
{
endPos = beginPos + keyWord.length();
}
else if(_workingString.length() > beginPos + keyWord.length() && Character.isWhitespace(_workingString.charAt(beginPos + keyWord.length())))
{
endPos = beginPos + keyWord.length();
}
else
{
return false;
}
return keyWord.equalsIgnoreCase(_workingString.substring(beginPos, endPos));
}
private int getTokenEnd(int errPos)
{
int ret = errPos;
while(_workingString.length() > ret && false == Character.isWhitespace(_workingString.charAt(ret)))
{
++ret;
}
return ret;
}
private int getPos(int line, int column)
{
int ix = 0;
///////////////////////////////////////////
// find the place where the error occured
for (int i = 0; i < line-1; i++)
{
ix =_workingString.indexOf('\n', ix) + 1;
}
ix += column;
//
///////////////////////////////////////////
return ix;
}
public void notifyParser(String sqlText)
{
synchronized(this)
{
_pendingString = sqlText;
this.notify();
}
}
public void exitThread()
{
_exitThread = true;
synchronized(this)
{
this.notify();
}
}
public void setParsingFinishedListener(ParsingFinishedListener parsingFinishedListener)
{
_parsingFinishedListener = parsingFinishedListener;
}
public void run()
{
try
{
while(true)
{
synchronized(this)
{
this.wait();
_workingString = _pendingString;
_workingBuffer = new IncrementalBuffer(new StringCharacterIterator(_workingString));
}
if(_exitThread)
{
break;
}
//////////////////////////////////////////////////////////////
// On Errors we restart the parser behind the error
_errorDetected = false;
runParser();
while(_errorDetected)
{
if(_workingString.length() > _nextStatBegin)
{
_workingString = _workingString.substring(_nextStatBegin, _workingString.length());
if("".equals(_workingString.trim()))
{
break;
}
}
else
{
break;
}
// if(_workingString.length() > _lastErrEnd)
// {
// _workingString = _workingString.substring(_lastErrEnd, _workingString.length());
// if("".equals(_workingString.trim()))
// {
// break;
// }
// }
// else
// {
// break;
// }
_lastParserRunOffset += _nextStatBegin;
_workingBuffer = new IncrementalBuffer(new StringCharacterIterator(_workingString));
_errorDetected = false;
runParser();
}
//
////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
// We are through with parsing. Now we store the outcome
// in _lastRun... and tell the listeners.
_lastRunTableAliasInfos = (TableAliasInfo[]) _workingTableAliasInfos.toArray(new TableAliasInfo[_workingTableAliasInfos.size()]);
_lastRunErrorInfos = (ErrorInfo[]) _workingErrorInfos.toArray(new ErrorInfo[_workingErrorInfos.size()]);
_workingTableAliasInfos.clear();
_workingErrorInfos.clear();
_lastParserRunOffset = 0;
if(null != _parsingFinishedListener)
{
_parsingFinishedListener.parsingFinished();
}
//
/////////////////////////////////////////////////////////////
if(_exitThread)
{
break;
}
}
}
catch (Exception e)
{
if(null != _parsingFinishedListener)
{
_parsingFinishedListener.parserExitedOnException(e);
}
e.printStackTrace();
}
}
private void runParser()
{
_errors.reset();
Scanner scanner = new Scanner(_workingBuffer, _errors);
Parser parser = new Parser(scanner);
parser.rootSchema = _schema;
parser.addParserListener(new ParserListener()
{
public void statementAdded(SQLStatement statement)
{
onStatementAdded(statement);
}
});
parser.addSQLSelectStatementListener(new SQLSelectStatementListener()
{
public void aliasDefined(String tableName, String aliasName)
{
onAliasDefined(tableName, aliasName);
}
});
parser.parse();
}
private void onStatementAdded(SQLStatement statement)
{
_curSQLSelectStat = statement;
}
private void onAliasDefined(String tableName, String aliasName)
{
_workingTableAliasInfos.add(new TableAliasInfo(aliasName, tableName, _curSQLSelectStat.getStart() + _lastParserRunOffset));
}
public TableAliasInfo[] getTableAliasInfos()
{
return _lastRunTableAliasInfos;
}
public ErrorInfo[] getErrorInfos()
{
return _lastRunErrorInfos;
}
/**
* reset the parser, starting a new parse on the characters given by the iterator
* @param chars the characters to start parsing from
*/
public void reset(CharacterIterator chars)
{
IncrementalBuffer oldBuffer = this._workingBuffer;
this._workingBuffer = new IncrementalBuffer(chars);
oldBuffer.eof();
}
/**
* terminate the parser
*/
public void end()
{
IncrementalBuffer oldBuffer = this._workingBuffer;
this._workingBuffer = null;
oldBuffer.eof();
}
/**
* accept the next character sequence to be parsed
* @param chars
*/
public void accept(CharacterIterator chars)
{
_workingBuffer.waitChars(); //wait for pending chars to be processed
_workingBuffer.accept(chars); //post new characters
}
/**
* This is a Scanner.Buffer implementation which blocks until character data is
* available. The {@link #read} method is invoked from the background parsing thread.
* The parsing thread can be terimated by calling the {@link #eof} method on this object
*/
private static class IncrementalBuffer extends Scanner.Buffer
{
private CharacterIterator chars;
private char current;
private boolean atEnd;
IncrementalBuffer(CharacterIterator chars)
{
this.atEnd = false;
this.chars = chars;
this.current = chars != null ? chars.first() : CharacterIterator.DONE;
}
/**
* read the next character. This method is invoked from the parser thread
* @return the next available character
*/
protected synchronized char read()
{
if (atEnd)
{
return eof;
}
else
{
if (current == CharacterIterator.DONE)
{
if (chars != null)
{
synchronized (chars)
{
chars.notify(); //tell the UI that this _workingBuffer is through
}
}
// try
// {
// wait();
// }
// catch (InterruptedException e)
// {
// }
}
if (atEnd)
{
current = eof;
return eof;
}
else
{
char prev = current;
//System.out.print(prev);
current = chars.next();
return prev;
}
}
}
synchronized void eof()
{
atEnd = true;
notify();
}
/**
* Post a character sequence to be read. Notify the parser thread accordingly. Invoking
* this method should always be followed by a call to {@link #waitChars} to ensure that
* the character sequence is not overwritten before it has been fully processed.
* @param chars the chracters to be read
*/
synchronized void accept(CharacterIterator chars)
{
this.chars = chars;
this.current = chars != null ? chars.first() : CharacterIterator.DONE;
notify();
}
/**
* block the current thread until all characters from the current iterator have
* been processed
*/
void waitChars()
{
if (chars != null && current != CharacterIterator.DONE)
{
synchronized (chars)
{
try
{
chars.wait();
}
catch (InterruptedException e)
{
}
}
}
}
int getBeginIndex()
{
return chars != null ? chars.getBeginIndex() : 0;
}
}
/**
* error stream which simply saves the error codes and line info
* circularily in an array of fixed size, and notifies a listener
* if requested
*/
private static class Errors extends ErrorStream
{
private int[][] errorStore;
private int count;
private ErrorListener listener;
public Errors(ErrorListener listener)
{
this.listener = listener;
errorStore = new int[5][3];
}
protected void ParsErr(int n, int line, int col)
{
errorStore[count][0] = n;
errorStore[count][1] = line;
errorStore[count][2] = col;
count = (count + 1) % 5;
if (listener != null)
super.ParsErr(n, line, col);
}
protected void SemErr(int n, int line, int col)
{
errorStore[count][0] = n;
errorStore[count][1] = line;
errorStore[count][2] = col;
count = (count + 1) % 5;
if (listener != null)
{
switch (n)
{
case 10:
StoreError(n, line, col, "undefined table");
break;
default:
super.SemErr(n, line, col);
}
}
}
protected void StoreError(int n, int line, int col, String s)
{
if (listener != null)
listener.errorDetected(s, line, col);
}
public void reset()
{
errorStore = new int[5][3];
}
}
}
--- NEW FILE: ParserLogger.java ---
package net.sourceforge.squirrel_sql.client.session.parser.kernel;
public class ParserLogger
{
public static void log(String log)
{
//System.out.println(log);
}
}
--- NEW FILE: ParserListener.java ---
package net.sourceforge.squirrel_sql.client.session.parser.kernel;
import net.sourceforge.squirrel_sql.client.session.parser.kernel.completions.SQLStatement;
public interface ParserListener
{
void statementAdded(SQLStatement statement);
}
--- NEW FILE: ErrorInfo.java ---
package net.sourceforge.squirrel_sql.client.session.parser.kernel;
public class ErrorInfo
{
public String message;
public int beginPos;
public int endPos;
private String key;
public ErrorInfo(String message, int beginPos, int endPos)
{
this.message = message;
this.beginPos = beginPos;
this.endPos = endPos;
key = message + "_" + beginPos + "_" + endPos;
}
public int hashCode()
{
return key.hashCode();
}
public boolean equals(Object obj)
{
ErrorInfo other = (ErrorInfo) obj;
return key.equals(other.key);
}
}
--- NEW FILE: ErrorStream.java ---
package net.sourceforge.squirrel_sql.client.session.parser.kernel;
public class ErrorStream {
int count; // number of errors detected
public String fileName;
public ErrorStream() {
count = 0;
}
protected void StoreError(int n, int line, int col, String s) {
System.out.println(fileName + " (" + line + ", " + col + ") " + s);
}
protected void ParsErr(int n, int line, int col) {
String s;
count++;
switch (n) {
case 0: {s = "EOF expected"; break;}
case 1: {s = "ident expected"; break;}
case 2: {s = "intValue expected"; break;}
case 3: {s = "float expected"; break;}
case 4: {s = "SQLString expected"; break;}
case 5: {s = "OpenParens expected"; break;}
case 6: {s = "\";\" expected"; break;}
case 7: {s = "\"UNION\" expected"; break;}
case 8: {s = "\"EXCEPT\" expected"; break;}
case 9: {s = "\"INTERSECT\" expected"; break;}
case 10: {s = "\"MINUS\" expected"; break;}
case 11: {s = "\"ALL\" expected"; break;}
case 12: {s = "\"UPDATE\" expected"; break;}
case 13: {s = "\"SET\" expected"; break;}
case 14: {s = "\"=\" expected"; break;}
case 15: {s = "\"INSERT\" expected"; break;}
case 16: {s = "\"INTO\" expected"; break;}
case 17: {s = "\"VALUES\" expected"; break;}
case 18: {s = "\"DELETE\" expected"; break;}
case 19: {s = "\"FROM\" expected"; break;}
case 20: {s = "\"SELECT\" expected"; break;}
case 21: {s = "\"DISTINCT\" expected"; break;}
case 22: {s = "\".\" expected"; break;}
case 23: {s = "\"AS\" expected"; break;}
case 24: {s = "\"JOIN\" expected"; break;}
case 25: {s = "\"CROSS\" expected"; break;}
case 26: {s = "\"NATURAL\" expected"; break;}
case 27: {s = "\"INNER\" expected"; break;}
case 28: {s = "\"FULL\" expected"; break;}
case 29: {s = "\"LEFT\" expected"; break;}
case 30: {s = "\"RIGHT\" expected"; break;}
case 31: {s = "\"OUTER\" expected"; break;}
case 32: {s = "\"ON\" expected"; break;}
case 33: {s = "\"USING\" expected"; break;}
case 34: {s = "\"WHERE\" expected"; break;}
case 35: {s = "\"GROUP\" expected"; break;}
case 36: {s = "\"BY\" expected"; break;}
case 37: {s = "\"HAVING\" expected"; break;}
case 38: {s = "\"ORDER\" expected"; break;}
case 39: {s = "\"*\" expected"; break;}
case 40: {s = "\"TIMESTAMP\" expected"; break;}
case 41: {s = "\"UPPER\" expected"; break;}
case 42: {s = "\"MONTH\" expected"; break;}
case 43: {s = "\"YEAR\" expected"; break;}
case 44: {s = "\"COUNT\" expected"; break;}
case 45: {s = "\"SUM\" expected"; break;}
case 46: {s = "\"MAX\" expected"; break;}
case 47: {s = "\"MIN\" expected"; break;}
case 48: {s = "\"AVG\" expected"; break;}
case 49: {s = "\"NULL\" expected"; break;}
case 50: {s = "\"DESC\" expected"; break;}
case 51: {s = "\"ASC\" expected"; break;}
case 52: {s = "\"-\" expected"; break;}
case 53: {s = "\":\" expected"; break;}
case 54: {s = "\"NOT\" expected"; break;}
case 55: {s = "\"/\" expected"; break;}
case 56: {s = "\"+\" expected"; break;}
case 57: {s = "\"AND\" expected"; break;}
case 58: {s = "\"OR\" expected"; break;}
case 59: {s = "\"LIKE\" expected"; break;}
case 60: {s = "\"ESCAPE\" expected"; break;}
case 61: {s = "\"IS\" expected"; break;}
case 62: {s = "\"<>\" expected"; break;}
case 63: {s = "\"<\" expected"; break;}
case 64: {s = "\"<=\" expected"; break;}
case 65: {s = "\">\" expected"; break;}
case 66: {s = "\">=\" expected"; break;}
case 67: {s = "\"BETWEEN\" expected"; break;}
case 68: {s = "\"IN\" expected"; break;}
case 69: {s = "\"COMMIT\" expected"; break;}
case 70: {s = "\"ROLLBACK\" expected"; break;}
case 71: {s = "\"WORK\" expected"; break;}
case 72: {s = "\"CHAR\" expected"; break;}
case 73: {s = "\"CHARACTER\" expected"; break;}
case 74: {s = "\"VARCHAR\" expected"; break;}
case 75: {s = "\"INTEGER\" expected"; break;}
case 76: {s = "\"INT\" expected"; break;}
case 77: {s = "\"SMALLINT\" expected"; break;}
case 78: {s = "\"NUMERIC\" expected"; break;}
case 79: {s = "\"DATE\" expected"; break;}
case 80: {s = "\"TIME\" expected"; break;}
case 81: {s = "\"DEFAULT\" expected"; break;}
case 82: {s = "\"PRIMARY\" expected"; break;}
case 83: {s = "\"KEY\" expected"; break;}
case 84: {s = "\"FOREIGN\" expected"; break;}
case 85: {s = "\"REFERENCES\" expected"; break;}
case 86: {s = "\"MATCH\" expected"; break;}
case 87: {s = "\"PARTIAL\" expected"; break;}
case 88: {s = "\"CASCADE\" expected"; break;}
case 89: {s = "\"NO\" expected"; break;}
case 90: {s = "\"ACTION\" expected"; break;}
case 91: {s = "\"UNIQUE\" expected"; break;}
case 92: {s = "\"CHECK\" expected"; break;}
case 93: {s = "\"CREATE\" expected"; break;}
case 94: {s = "\"TABLE\" expected"; break;}
case 95: {s = "\"RESTRICT\" expected"; break;}
case 96: {s = "\"DROP\" expected"; break;}
case 97: {s = "\"ADD\" expected"; break;}
case 98: {s = "\"ALTER\" expected"; break;}
case 99: {s = "\"CONSTRAINT\" expected"; break;}
case 100: {s = "\"INDEX\" expected"; break;}
case 101: {s = "\",\" expected"; break;}
case 102: {s = "\")\" expected"; break;}
case 103: {s = "not expected"; break;}
case 104: {s = "invalid DropPart"; break;}
case 105: {s = "invalid Alter"; break;}
case 106: {s = "invalid Add"; break;}
case 107: {s = "invalid CascadeRestrict"; break;}
case 108: {s = "invalid CreatePart"; break;}
case 109: {s = "invalid ForeignKey"; break;}
case 110: {s = "invalid ForeignKey"; break;}
case 111: {s = "invalid ForeignKey"; break;}
case 112: {s = "invalid ForeignKey"; break;}
case 113: {s = "invalid ColumnDefault"; break;}
case 114: {s = "invalid DataType"; break;}
case 115: {s = "invalid InSetExpr"; break;}
case 116: {s = "invalid LikeTest"; break;}
case 117: {s = "invalid WordOperator"; break;}
case 118: {s = "invalid MathOperator"; break;}
case 119: {s = "invalid TestExpr"; break;}
case 120: {s = "invalid TestExpr"; break;}
case 121: {s = "invalid Operator"; break;}
case 122: {s = "invalid Term"; break;}
case 123: {s = "invalid Term"; break;}
case 124: {s = "invalid Relation"; break;}
case 125: {s = "invalid OrderByField"; break;}
case 126: {s = "invalid Field"; break;}
case 127: {s = "invalid ColumnFunction"; break;}
case 128: {s = "invalid ColumnFunction"; break;}
case 129: {s = "invalid FunctionExpr"; break;}
case 130: {s = "invalid SelectField"; break;}
case 131: {s = "invalid JoinExpr"; break;}
case 132: {s = "invalid JoinType"; break;}
case 133: {s = "invalid JoinStmt"; break;}
case 134: {s = "this symbol not expected in OrderByClause"; break;}
case 135: {s = "this symbol not expected in HavingClause"; break;}
case 136: {s = "this symbol not expected in GroupByClause"; break;}
case 137: {s = "this symbol not expected in FromClause"; break;}
case 138: {s = "this symbol not expected in SelectClause"; break;}
case 139: {s = "invalid ColumnName"; break;}
case 140: {s = "this symbol not expected in WhereClause"; break;}
case 141: {s = "invalid SetOperator"; break;}
case 142: {s = "invalid Transaction"; break;}
case 143: {s = "invalid AlterTable"; break;}
case 144: {s = "invalid Drop"; break;}
case 145: {s = "invalid CreateStmt"; break;}
case 146: {s = "invalid InsertStmt"; break;}
case 147: {s = "invalid SQLStatement"; break;}
default: s = "Syntax error " + n;
}
StoreError(n, line, col, s);
}
protected void SemErr(int n, int line, int col) {
String s;
count++;
switch (n) {
// for example: case 0: s = "invalid character"; break;
// perhaps insert application specific error messages here
default: s = "Semantic error " + n; break;
}
StoreError(n, line, col, s);
}
protected void Exception (String s) {
throw new RuntimeException(s);
}
protected void Summarize () {
switch (count) {
case 0 : ParserLogger.log("No errors detected"); break;
case 1 : ParserLogger.log("1 error detected"); break;
default: ParserLogger.log(count + " errors detected"); break;
}
}
}
--- NEW FILE: RestartInfo.java ---
package net.sourceforge.squirrel_sql.client.session.parser.kernel;
public class RestartInfo
{
}
--- NEW FILE: Parser.java ---
package net.sourceforge.squirrel_sql.client.session.parser.kernel;
import net.sourceforge.squirrel_sql.client.session.parser.kernel.completions.*;
import java.util.*;
public class Parser
{
private static final int maxT = 103;
private static final int maxP = 103;
private static final boolean T = true;
private static final boolean x = false;
private static final int minErrDist = 2;
private int errDist = minErrDist;
private Vector parserListeners = new Vector();
private Vector sqlSelectStatlisteners = new Vector();
[...1701 lines suppressed...]
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x},
{x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, T, x, T, T, T, T, T, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x},
{x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, T, T, T, T, T, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x},
{x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, T, T, T, T, T, T, T, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, T, x, x, x},
{T, x, x, x, x, x, T, T, T, T, T, x, T, x, T, T, x, T, T, T, T, x, x, T, T, T, T, T, T, T, T, x, x, x, T, T, x, T, T, T, x, x, x, x, x, x, x, x, x, x, x, x, T, x, T, T, T, T, T, x,
x, x, T, T, T, T, T, x, x, T, T, x, x, x, x, x, x, x, x, x, x, T, x, x, x, T, x, x, x, x, x, x, x, T, x, x, T, x, T, x, x, T, T, x, x},
{x, x, x, x, x, x, x, x, x, x, x, x, x, x, T, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, T, T, T, T, T, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x},
{T, T, T, T, T, T, x, x, x, x, x, x, x, x, x, x, x, x, x, T, T, x, x, x, x, x, x, x, x, x, x, x, x, x, T, T, x, T, T, T, T, T, T, T, T, T, T, T, T, T, x, x, T, T, T, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, T, x, T, x, x, x, x, x, x, T, T, x, x, x, x, x, x, x, x, x, x, x, x},
{x, x, x, x, x, x, x, T, T, T, T, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x},
{x, x, x, x, x, x, x, x, x, x, x, x, T, x, x, T, x, x, T, x, T, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, T, T, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, T, x, x, T, x, T, x, x, x, x, x, x}
};
}
--- NEW FILE: SQLSchema.java ---
/*
* Copyright (C) 2002 Christian Sell
* cs...@us...
*
* 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
*
* created by cse, 24.09.2002 17:30:57
*/
package net.sourceforge.squirrel_sql.client.session.parser.kernel;
import java.util.List;
import java.util.ArrayList;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* requirements for objects that maintain schema information
*/
public interface SQLSchema
{
/**
* a descriptor which groups together information about a database table
*/
public class Table implements Cloneable, Comparable
{
public final String catalog;
public final String schema;
public final String name;
public final String compositeName;
public transient String alias;
private DatabaseMetaData dmd;
private String[] columns;
public static String createCompositeName(String catalog, String schema, String name)
{
StringBuffer sbuf = new StringBuffer();
if(catalog != null) {
sbuf.append(catalog);
sbuf.append(".");
}
if(schema != null) {
sbuf.append(schema);
sbuf.append(".");
}
sbuf.append(name);
return sbuf.toString();
}
public Table clone(String alias)
{
try {
Table newTable = (Table)super.clone();
newTable.alias = alias;
return newTable;
}
catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
public Table(String catalog, String schema, String name, DatabaseMetaData dmd)
{
this.catalog = catalog;
this.schema = schema;
this.name = name;
this.compositeName = createCompositeName(catalog, schema, name);
this.dmd = dmd;
}
public Table(String catalog, String schema, String name)
{
this(catalog, schema, name, null);
}
public Table(String schema, String name)
{
this(null, schema, name, null);
}
public Table(String name)
{
this(null, null, name, null);
}
public void setColumns(String[] columns)
{
this.columns = columns;
}
public void setColumns(List columns)
{
this.columns = (String[])columns.toArray(new String[columns.size()]);
}
public String[] getColumns()
{
if(columns == null) loadColumns();
return columns;
}
public String[] getColumns(String prefix)
{
String[] cols = getColumns();
if(prefix == null) return cols;
List list = new ArrayList(cols.length);
for(int i=0; i<cols.length; i++)
if(cols[i].startsWith(prefix)) list.add(cols[i]);
return (String[])list.toArray(new String[list.size()]);
}
public String getCompositeName()
{
return compositeName;
}
public boolean hasAlias()
{
return alias != null;
}
public String toString()
{
return alias == null ? compositeName : compositeName + " "+alias;
}
public int hashCode()
{
return compositeName.hashCode();
}
public boolean equals(Object other)
{
if(other instanceof Table) {
Table o = (Table)other;
if(o.compositeName.equals(compositeName)) {
return alias == o.alias || alias != null && alias.equals(o.alias);
}
else return false;
}
else return false;
}
public boolean equals(String catalog, String schema, String table)
{
return
(this.catalog == catalog ||
(this.catalog != null && catalog != null && this.catalog.equals(catalog))) &&
(this.schema == schema ||
(this.schema != null && schema != null && this.schema.equals(schema))) &&
(this.name.equals(table));
}
public boolean matches(String catalog, String schema, String name)
{
return
(catalog == null ||
(this.catalog != null && this.catalog.startsWith(catalog))) &&
(schema == null ||
(this.schema != null && this.schema.startsWith(schema))) &&
(name == null || this.name.startsWith(name));
}
public int compareTo(Object o)
{
Table other = (Table)o;
if(alias != null) {
return other.alias != null ? alias.compareTo(other.alias) : -1;
}
else if(other.alias != null) {
return 1;
}
return compositeName.compareTo(other.compositeName);
}
protected void loadColumns()
{
ResultSet rs = null;
try {
List cols = new ArrayList();
rs = dmd.getColumns(catalog, schema, name, null);
while(rs.next())
{
cols.add(rs.getString(4));
}
setColumns(cols);
}
catch (SQLException e) {
throw new RuntimeException(e.getMessage());
}
finally {
if(rs != null) try {rs.close();} catch(SQLException e) {}
}
}
}
/**
* lookup a table descriptor which exactly matches the parameters
* @param catalog optional
* @param schema optional
* @param name required
* @return the table descriptor
*/
Table getTable(String catalog, String schema, String name);
/**
* Return tables matching a pattern. If a <em>pattern</em> is null it is not
* considered. If all patterns are null, all tables are returned
* @param catalog catalog name pattern (optional)
* @param schema schema name pattern (optional)
* @param name name pattern (optional)
* @return descriptors for tables matching the parameters
*/
List getTables(String catalog, String schema, String name);
/**
* @param alias an alias, possibly also the table name itself
* @return the table registered under the given alias/name
*/
Table getTableForAlias(String alias);
}
--- NEW FILE: ParsingFinishedListener.java ---
package net.sourceforge.squirrel_sql.client.session.parser.kernel;
public interface ParsingFinishedListener
{
void parsingFinished();
void parserExitedOnException(Throwable e);
}
--- NEW FILE: Scanner.java ---
package net.sourceforge.squirrel_sql.client.session.parser.kernel;
import net.sourceforge.squirrel_sql.client.session.parser.kernel.ErrorStream;
import java.io.*;
import java.util.*;
class Token {
int kind; // token kind
int pos; // token position in the source text (starting at 0)
int col; // token column (starting at 0)
int line; // token line (starting at 1)
String str; // exact string value
String val; // token string value (uppercase if ignoreCase)
}
public class Scanner
{
public abstract static class Buffer
{
public static final char eof = 65535;
int _bufLen;
int _pos;
protected void setIndex(int position) {
if (position < 0) position = 0; else if (position >= _bufLen) position = _bufLen;
_pos = position;
}
protected abstract char read();
}
static class FBuffer extends Buffer
{
static char[] buf;
FBuffer(File file) throws IOException
{
_bufLen = (int) file.length();
FileReader fr = new FileReader(file);
buf = new char[_bufLen];
fr.read(buf);
_pos = 0;
}
protected char read() {
if (_pos < _bufLen) return buf[_pos++];
else return eof;
}
}
static class SBuffer extends Buffer
{
String chars;
SBuffer(String string)
{
_bufLen = string.length();
chars = string;
_pos = 0;
}
protected char read() {
if (_pos < _bufLen)
return chars.charAt(_pos++);
else return eof;
}
}
private static final char EOF = '\0';
private static final char CR = '\r';
private static final char LF = '\n';
private static final int noSym = 103;
private static final int[] start = {
23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 4, 1, 1, 0, 0, 5, 7, 22, 11, 15, 21, 12, 2, 14,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 13, 9, 16, 10, 19, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
0};
// set of characters to be ignored by the scanner
private static BitSet ignore = new BitSet(128);
static {
ignore.set(1); ignore.set(2); ignore.set(3); ignore.set(4);
ignore.set(5); ignore.set(6); ignore.set(7); ignore.set(8);
ignore.set(9); ignore.set(10); ignore.set(11); ignore.set(12);
ignore.set(13); ignore.set(14); ignore.set(15); ignore.set(16);
ignore.set(17); ignore.set(18); ignore.set(19); ignore.set(20);
ignore.set(21); ignore.set(22); ignore.set(23); ignore.set(24);
ignore.set(25); ignore.set(26); ignore.set(27); ignore.set(28);
ignore.set(29); ignore.set(30); ignore.set(31); ignore.set(32);
}
ErrorStream err; // error messages
private Buffer buf; // data, random accessible
protected Token t; // current token
protected char strCh; // current input character (original)
protected char ch; // current input character (for token)
protected char lastCh; // last input character
protected int pos; // position of current character
protected int line; // line number of current character
protected int lineStart; // start position of current line
public Scanner (File file, ErrorStream e) throws IOException
{
buf = new FBuffer(file);
init(e, file.getName());
}
public Scanner (String parseString, ErrorStream e)
{
buf = new SBuffer(parseString);
init(e, "");
}
public Scanner (Buffer buff, ErrorStream e)
{
this.buf = buff;
init(e, "");
}
private void init(ErrorStream e, String eName) {
err = e;
err.fileName = eName;
pos = -1; line = 1; lineStart = 0; lastCh = 0;
NextCh();
}
void setPos(int position) {
buf.setIndex(position);
}
private void NextCh() {
lastCh = ch;
strCh = buf.read(); pos++;
ch = Character.toUpperCase(strCh);
if (ch == '\uffff') ch = EOF;
else if (ch == CR) {line++; lineStart = pos + 1;}
else if (ch == LF) {
if (lastCh != CR) line++;
lineStart = pos + 1;
} else if (ch > '\u007f') {
err.StoreError(0, line, pos - lineStart + 1, "invalid character in source file");
err.count++; ch = ' ';
}
}
private final boolean Comment0() {
int level = 1, line0 = line, lineStart0 = lineStart; char startCh;
NextCh();
if (ch == '-') {
NextCh();
for(;;) {
if (ch == 13) {
level--;
if (level == 0) {NextCh(); return true;}
NextCh();
} else if (ch == EOF) return false;
else NextCh();
}
} else {
if (ch == CR || ch == LF) {line--; lineStart = lineStart0;}
pos = pos - 2; setPos(pos+1); NextCh();
}
return false;
}
private final boolean Comment1() {
int level = 1, line0 = line, lineStart0 = lineStart; char startCh;
NextCh();
if (ch == '*') {
NextCh();
for(;;) {
if (ch == '*') {
NextCh();
if (ch == '/') {
level--;
if (level == 0) {NextCh(); return true;}
NextCh();
}
} else if (ch == '/') {
NextCh();
if (ch == '*') {
level++; NextCh();
}
} else if (ch == EOF) return false;
else NextCh();
}
} else {
if (ch == CR || ch == LF) {line--; lineStart = lineStart0;}
pos = pos - 2; setPos(pos+1); NextCh();
}
return false;
}
private void CheckLiteral(StringBuffer buf) {
t.val = buf.toString().toUpperCase();
switch (t.val.charAt(0)) {
case 'A': {
if (t.val.equals("ACTION")) t.kind = 90;
else if (t.val.equals("ADD")) t.kind = 97;
else if (t.val.equals("ALL")) t.kind = 11;
else if (t.val.equals("ALTER")) t.kind = 98;
else if (t.val.equals("AND")) t.kind = 57;
else if (t.val.equals("AS")) t.kind = 23;
else if (t.val.equals("ASC")) t.kind = 51;
else if (t.val.equals("AVG")) t.kind = 48;
break;}
case 'B': {
if (t.val.equals("BETWEEN")) t.kind = 67;
else if (t.val.equals("BY")) t.kind = 36;
break;}
case 'C': {
if (t.val.equals("CASCADE")) t.kind = 88;
else if (t.val.equals("CHAR")) t.kind = 72;
else if (t.val.equals("CHARACTER")) t.kind = 73;
else if (t.val.equals("CHECK")) t.kind = 92;
else if (t.val.equals("COMMIT")) t.kind = 69;
else if (t.val.equals("CONSTRAINT")) t.kind = 99;
else if (t.val.equals("COUNT")) t.kind = 44;
else if (t.val.equals("CREATE")) t.kind = 93;
else if (t.val.equals("CROSS")) t.kind = 25;
break;}
case 'D': {
if (t.val.equals("DATE")) t.kind = 79;
else if (t.val.equals("DEFAULT")) t.kind = 81;
else if (t.val.equals("DELETE")) t.kind = 18;
else if (t.val.equals("DESC")) t.kind = 50;
else if (t.val.equals("DISTINCT")) t.kind = 21;
else if (t.val.equals("DROP")) t.kind = 96;
break;}
case 'E': {
if (t.val.equals("ESCAPE")) t.kind = 60;
else if (t.val.equals("EXCEPT")) t.kind = 8;
break;}
case 'F': {
if (t.val.equals("FOREIGN")) t.kind = 84;
else if (t.val.equals("FROM")) t.kind = 19;
else if (t.val.equals("FULL")) t.kind = 28;
break;}
case 'G': {
if (t.val.equals("GROUP")) t.kind = 35;
break;}
case 'H': {
if (t.val.equals("HAVING")) t.kind = 37;
break;}
case 'I': {
if (t.val.equals("IN")) t.kind = 68;
else if (t.val.equals("INDEX")) t.kind = 100;
else if (t.val.equals("INNER")) t.kind = 27;
else if (t.val.equals("INSERT")) t.kind = 15;
else if (t.val.equals("INT")) t.kind = 76;
else if (t.val.equals("INTEGER")) t.kind = 75;
else if (t.val.equals("INTERSECT")) t.kind = 9;
else if (t.val.equals("INTO")) t.kind = 16;
else if (t.val.equals("IS")) t.kind = 61;
break;}
case 'J': {
if (t.val.equals("JOIN")) t.kind = 24;
break;}
case 'K': {
if (t.val.equals("KEY")) t.kind = 83;
break;}
case 'L': {
if (t.val.equals("LEFT")) t.kind = 29;
else if (t.val.equals("LIKE")) t.kind = 59;
break;}
case 'M': {
if (t.val.equals("MATCH")) t.kind = 86;
else if (t.val.equals("MAX")) t.kind = 46;
else if (t.val.equals("MIN")) t.kind = 47;
else if (t.val.equals("MINUS")) t.kind = 10;
else if (t.val.equals("MONTH")) t.kind = 42;
break;}
case 'N': {
if (t.val.equals("NATURAL")) t.kind = 26;
else if (t.val.equals("NO")) t.kind = 89;
else if (t.val.equals("NOT")) t.kind = 54;
else if (t.val.equals("NULL")) t.kind = 49;
else if (t.val.equals("NUMERIC")) t.kind = 78;
break;}
case 'O': {
if (t.val.equals("ON")) t.kind = 32;
else if (t.val.equals("OR")) t.kind = 58;
else if (t.val.equals("ORDER")) t.kind = 38;
else if (t.val.equals("OUTER")) t.kind = 31;
break;}
case 'P': {
if (t.val.equals("PARTIAL")) t.kind = 87;
else if (t.val.equals("PRIMARY")) t.kind = 82;
break;}
case 'R': {
if (t.val.equals("REFERENCES")) t.kind = 85;
else if (t.val.equals("RESTRICT")) t.kind = 95;
else if (t.val.equals("RIGHT")) t.kind = 30;
else if (t.val.equals("ROLLBACK")) t.kind = 70;
break;}
case 'S': {
if (t.val.equals("SELECT")) t.kind = 20;
else if (t.val.equals("SET")) t.kind = 13;
else if (t.val.equals("SMALLINT")) t.kind = 77;
else if (t.val.equals("SUM")) t.kind = 45;
break;}
case 'T': {
if (t.val.equals("TABLE")) t.kind = 94;
else if (t.val.equals("TIME")) t.kind = 80;
else if (t.val.equals("TIMESTAMP")) t.kind = 40;
break;}
case 'U': {
if (t.val.equals("UNION")) t.kind = 7;
else if (t.val.equals("UNIQUE")) t.kind = 91;
else if (t.val.equals("UPDATE")) t.kind = 12;
else if (t.val.equals("UPPER")) t.kind = 41;
else if (t.val.equals("USING")) t.kind = 33;
break;}
case 'V': {
if (t.val.equals("VALUES")) t.kind = 17;
else if (t.val.equals("VARCHAR")) t.kind = 74;
break;}
case 'W': {
if (t.val.equals("WHERE")) t.kind = 34;
else if (t.val.equals("WORK")) t.kind = 71;
break;}
case 'Y': {
if (t.val.equals("YEAR")) t.kind = 43;
break;}
}
}
Token Scan() {
while (ignore.get((int)ch)) NextCh();
if (ch == '-' && Comment0() || ch == '/' && Comment1() ) return Scan();
t = new Token();
t.pos = pos; t.col = pos - lineStart + 1; t.line = line;
StringBuffer buf = new StringBuffer();
int state = start[ch];
int apx = 0;
loop: for (;;) {
buf.append(strCh);
NextCh();
switch (state) {
case 0:
{t.kind = noSym; break loop;} // NextCh already done
case 1:
if ((ch == '!'
|| ch >= '#' && ch <= '$'
|| ch >= '0' && ch <= '9'
|| ch >= '@' && ch <= '{'
|| ch >= '}')) {break;}
else {t.kind = 1; CheckLiteral(buf); break loop;}
case 2:
if ((ch >= '0' && ch <= '9')) {state = 3; break;}
else {t.kind = 22; break loop;}
case 3:
if ((ch >= '0' && ch <= '9')) {break;}
else {t.kind = 3; break loop;}
case 4:
if ((ch >= ' ' && ch <= '!'
|| ch >= '#')) {break;}
else if (ch == '"') {state = 6; break;}
else {t.kind = noSym; break loop;}
case 5:
if ((ch >= ' ' && ch <= '&'
|| ch >= '(')) {break;}
else if (ch == 39) {state = 6; break;}
else {t.kind = noSym; break loop;}
case 6:
{t.kind = 4; break loop;}
case 7:
{t.kind = 5; break loop;}
case 8:
if ((ch >= '0' && ch <= '9')) {break;}
else if (ch == '.') {state = 2; break;}
else {t.kind = 2; break loop;}
case 9:
{t.kind = 6; break loop;}
case 10:
{t.kind = 14; break loop;}
case 11:
{t.kind = 39; break loop;}
case 12:
{t.kind = 52; break loop;}
case 13:
{t.kind = 53; break loop;}
case 14:
{t.kind = 55; break loop;}
case 15:
{t.kind = 56; break loop;}
case 16:
if (ch == '>') {state = 17; break;}
else if (ch == '=') {state = 18; break;}
else {t.kind = 63; break loop;}
case 17:
{t.kind = 62; break loop;}
case 18:
{t.kind = 64; break loop;}
case 19:
if (ch == '=') {state = 20; break;}
else {t.kind = 65; break loop;}
case 20:
{t.kind = 66; break loop;}
case 21:
{t.kind = 101; break loop;}
case 22:
{t.kind = 102; break loop;}
case 23:
{t.kind = 0; break loop;}
}
}
t.str = buf.toString();
t.val = t.str.toUpperCase();
return t;
}
}
--- NEW FILE: SQLCompletion.java ---
/*
* Copyright (C) 2002 Christian Sell
* cs...@us...
*
* 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
*
* created by cse, 24.09.2002 12:00:04
*
* @version $Id: SQLCompletion.java,v 1.1 2004/04/04 10:36:31 colbell Exp $
*/
package net.sourceforge.squirrel_sql.client.session.parser.kernel;
/**
* abstract superclass for completion items
*/
public abstract class SQLCompletion implements Completion
{
public static final int NO_POSITION = -1;
public static final int NO_LIMIT = 99999;
public static final String[] EMPTY_RESULT = new String[0];
protected int startPosition=NO_POSITION, endPosition=NO_LIMIT;
protected SQLCompletion(int startPosition)
{
this.startPosition = startPosition;
}
protected SQLCompletion() {}
public Completion getCompletion(int position)
{
return isEnclosed(position) ? this : null;
}
/**
* @return whether this object reperesents a concrete item, as opposed to being a
* placeholder for potential items. For example, a non-concrete item may be inserted
* into the completion tree to allow inserting completions in a certain text area. A
* concrete item should be created when the parser encounters an existing item in the
* token stream. During {@link #getCompletion completion lookup}, concrete items are
* preferred before non-concrete ones
*/
protected boolean isConcrete()
{
return true;
}
public void setEndPosition(int position)
{
this.endPosition = position;
}
/**
* @return the completion text
* @throws UnsupportedOperationException
*/
public String getText(int position)
{
throw new UnsupportedOperationException("completion not available");
}
/**
* @return the completion text, provided it is available
* @throws UnsupportedOperationException
*/
public String getText(int position, String options)
{
throw new UnsupportedOperationException("completion not available");
}
public boolean hasTextPosition()
{
return startPosition != NO_POSITION && endPosition != NO_POSITION;
}
public boolean isRepeatable()
{
return false;
}
public int getLength()
{
return endPosition - startPosition + 1;
}
public int getStart()
{
return startPosition;
}
public boolean mustReplace(int position)
{
return false;
}
/**
* @param position the text position to be checked
* @return whether the given text position is enclosed by this objects range
*/
protected boolean isEnclosed(int position)
{
return position >= startPosition && position <= endPosition;
}
/**
* A comparator implementation which sorts descending according to startPosition,
* while preferring {@link #isConcrete concrete} items before non-concrete ones
*/
public class ChildComparator implements java.util.Comparator
{
public int compare(Object o1, Object o2)
{
SQLCompletion c1 = (SQLCompletion)o1;
SQLCompletion c2 = (SQLCompletion)o2;
if(c1.isConcrete() == c2.isConcrete())
return c2.startPosition - c1.startPosition ;
else return c1.isConcrete() ? -1 : 1;
}
}
}
--- NEW FILE: TableAliasInfo.java ---
package net.sourceforge.squirrel_sql.client.session.parser.kernel;
public class TableAliasInfo
{
public String aliasName;
public String tableName;
public int statBegin;
public TableAliasInfo(String aliasName, String tableName, int statBegin)
{
this.aliasName = aliasName;
this.tableName = tableName;
this.statBegin = statBegin;
}
}
--- NEW FILE: Completion.java ---
/*
* Copyright (C) 2002 Christian Sell
* cs...@us...
*
* 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
*
* created by cse, 24.09.2002 11:20:31
*
* @version $Id: Completion.java,v 1.1 2004/04/04 10:36:31 colbell Exp $
*/
package net.sourceforge.squirrel_sql.client.session.parser.kernel;
/**
* requirements of a completion item
*/
public interface Completion
{
/**
* Find a completion item for the given text position. This method can be overridden by
* subclasses to implement the composite pattern. If the object is not a composite, it
* should return itself. Otherwise, it can delegate the lookup to its children.
* @param position the caret position at which the completion is requested
* @return an appropriate completion object, or <em>null</em> of none available
*/
Completion getCompletion(int position);
/**
* return completion text if the completion is fully defined
* @param position the caret position at which the text should be inserted
* @return return the completion text to be inserted into the underlying document
*/
String getText(int position);
/**
* return completion text which is defined from this object and the derived option
* @param position the caret position at which the text should be inserted
* @param option an option string, which was earlier derived from this object
* @return return the completion text to be inserted into the underlying document
*/
String getText(int position, String option);
/**
* @return whether this completion is assigned to a specific position within the
* underlying document
*/
boolean hasTextPosition();
/**
* @return whether this completion can be used to generate lists of items, e.g. columns
* in a SQL select clause
*/
boolean isRepeatable();
/**
* @return the length of the text currently occupied by this completion
*/
int getLength();
/**
* @return the starting text position
*/
int getStart();
/**
* @param position the position at which the status should be determined
* @return whether the text between the start position and <em>position</em> must be replaced
*/
boolean mustReplace(int position);
}
|