synchronized protected void scanpass(TokenSource ts)
throws SqlToolError, SQLException {
boolean rollbackUncoms = true;
String nestingCommand;
Token token = null;
if (shared.userVars.size() > 0) {
plMode = true;
}
try {
while (true) try {
if (preempt) {
token = buffer;
preempt = false;
} else {
token = ts.yylex();
logger.finest("SqlFile got new token: " + token);
}
if (token == null) break;
nestingCommand = nestingCommand(token);
if (nestingCommand != null) {
if (token.nestedBlock == null) {
token.nestedBlock = seekTokenSource(nestingCommand);
/* This command (and the same recursive call inside
* of the seekTokenSource() method) ensure that all
* "blocks" are tokenized immediately as block
* commands are encountered, and the blocks are
* tokenized in their entirety all the way to the
* leaves.
*/
}
processBlock(token);
/* processBlock recurses through scanpass(),
* which processes the nested commands which have
* (in all cases) already beeen tokenized.
*/
continue;
}
switch (token.type) {
case Token.SYNTAX_ERR_TYPE:
throw new SqlToolError(SqltoolRB.input_malformat.getString());
// Will get here if Scanner can't match input to any
// known command type.
// An easy way to get here is to start a command with
// quotes.
case Token.UNTERM_TYPE:
throw new SqlToolError(
SqltoolRB.input_unterminated.getString(
token.val));
case Token.RAW_TYPE:
case Token.RAWEXEC_TYPE:
/*
* A real problem in this block is that the Scanner
* has already displayed the next prompt at this
* point. We handle this specially within this
* block, but if we throw, the handler will not
* know that the prompt has to be re-displayed.
* I.e., KNOWN ISSUE: For some errors caught during
* raw command execution, interactive users will not
* get a prompt to tell them to proceed.
*/
if (token.val == null) token.val = "";
/*
* Don't have time know to figure out whether it would
* ever be useful to send just (non-zero) whitespace
* to the DB. Prohibiting for now.
*/
if (token.val.trim().length() < 1) {
throw new SqlToolError(
SqltoolRB.raw_empty.getString());
}
int receivedType = token.type;
token.type = Token.SQL_TYPE;
if (setBuf(token) && receivedType == Token.RAW_TYPE
&& interactive) {
stdprintln("");
stdprintln(SqltoolRB.raw_movedtobuffer.getString());
stdprint(primaryPrompt);
// All of these stdprint*'s are to work around a
// very complicated issue where the Scanner
// has already displayed the next prompt before
// we can display our status message.
}
if (receivedType == Token.RAWEXEC_TYPE) {
historize();
processSQL();
}
continue;
case Token.MACRO_TYPE:
processMacro(token);
continue;
case Token.PL_TYPE:
setBuf(token);
historize();
processPL(null);
continue;
case Token.SPECIAL_TYPE:
setBuf(token);
historize();
processSpecial(null);
continue;
case Token.EDIT_TYPE:
// Scanner only returns EDIT_TYPEs in interactive mode
processBuffHist(token);
continue;
case Token.BUFFER_TYPE:
token.type = Token.SQL_TYPE;
if (setBuf(token)) {
stdprintln(
SqltoolRB.input_movedtobuffer.getString());
}
continue;
case Token.SQL_TYPE:
if (token.val == null) token.val = "";
setBuf(token);
historize();
processSQL();
continue;
default:
throw new RuntimeException(
"Internal assertion failed. "
+ "Unexpected token type: "
+ token.getTypeString());
}
} catch (BadSpecial bs) {
// BadSpecials ALWAYS have non-null getMessage().
if (token == null) {
errprintln(SqltoolRB.errorat.getString(
inputStreamLabel, "?", "?", bs.getMessage()));
} else {
errprintln(SqltoolRB.errorat.getString(
inputStreamLabel,
Integer.toString(token.line),
token.reconstitute(),
bs.getMessage(), bs.getMessage()));
}
Throwable cause = bs.getCause();
if (cause != null) {
errprintln(SqltoolRB.causereport.getString(
cause.toString()));
}
if (!continueOnError) {
throw new SqlToolError(bs);
}
} catch (SQLException se) {
//se.printStackTrace();
errprintln("SQL " + SqltoolRB.errorat.getString(
inputStreamLabel,
((token == null) ? "?"
: Integer.toString(token.line)),
lastSqlStatement,
se.getMessage()));
// It's possible that we could have
// SQLException.getMessage() == null, but if so, I think
// it reasonable to show "null". That's a DB inadequacy.
if (!continueOnError) {
throw se;
}
} catch (BreakException be) {
String msg = be.getMessage();
if (recursed) {
rollbackUncoms = false;
// Recursion level will exit by rethrowing the BE.
// We set rollbackUncoms to false because only the
// top level should detect break errors and
// possibly roll back.
} else if (msg == null || msg.equals("file")) {
break;
} else {
errprintln(SqltoolRB.break_unsatisfied.getString(msg));
}
if (recursed ||!continueOnError) {
throw be;
}
} catch (ContinueException ce) {
String msg = ce.getMessage();
if (recursed) {
rollbackUncoms = false;
} else {
errprintln(SqltoolRB.continue_unsatisfied.getString(msg));
}
if (recursed ||!continueOnError) {
throw ce;
}
} catch (QuitNow qn) {
throw qn;
} catch (SqlToolError ste) {
StringBuffer sb = new StringBuffer(SqltoolRB.errorat.getString(
/* WARNING: I have removed an extra LS appended to
* non-null ste.getMessages() below because I believe that
* it is unnecessary (and causes inconsistent blank lines
* to be written).
* If I am wrong and this is needed for Scanner display or
* something, restore it.
*/
((token == null)
? (new String[] {
inputStreamLabel, "?", "?",
((ste.getMessage() == null)
? "" : ste.getMessage())
})
: (new String[] {
inputStreamLabel, Integer.toString(token.line),
((token.val == null) ? "" : token.reconstitute()),
((ste.getMessage() == null)
? "" : ste.getMessage())
}))
));
Throwable cause = ste.getCause();