origVals[i] = shared.userVars.get(vars[i]);
TokenList dupNesteds = token.nestedBlock.dup();
if (dupNesteds.size() < 2)
// TODO: Define message
throw new BadSpecial("Empty forrows loop");
Token queryToken = dupNesteds.remove(0);
if (queryToken.type != Token.SQL_TYPE)
// TODO: Define message
throw new BadSpecial("*forrows command not followed "
+ "immediately by an SQL statement");
setBuf(queryToken);
List<String[]> rowData = new ArrayList<String[]>();
ResultSet rs = null;
int colCount = 0;
Statement statement = processSQL();
if (statement == null)
// TODO: Define message
throw new BadSpecial("Failed to prepare SQL for loop");
try {
rs = statement.getResultSet();
ResultSetMetaData rsmd = rs.getMetaData();
colCount = rsmd.getColumnCount();
if (vars != null && vars.length > colCount)
// TODO: Define message
throw new BadSpecial("*forrows command specifies "
+ vars.length
+ " variables, but query pulled only "
+ colCount + " columns");
if (colCount < 1) return;
String[] rowCells;
while (rs.next()) {
rowCells = new String[colCount];
rowData.add(rowCells);
for (int i = 1; i <= colCount; i++)
rowCells[i-1] = rs.getString(i);
}
} finally {
try {
if (rs != null) rs.close();
} catch (SQLException nse) {
// Purposefully doing nothing
} finally {
rs = null;
}
try {
statement.close();
} catch (SQLException nse) {
// Purposefully doing nothing
} finally {
statement = null;
}
}
lastSqlStatement = null;
// Done with SQL
if (rowData.size() > 0) {
String firstVal = rowData.get(0)[0];
String lastVal = rowData.get(rowData.size()-1)[colCount - 1];
shared.userVars.put("?",
(lastVal == null) ? nullRepToken : lastVal);
if (fetchingVar != null) {
if (firstVal == null)
shared.userVars.remove(fetchingVar);
else
shared.userVars.put(fetchingVar, firstVal);
updateUserSettings();
sqlExpandMode = null;
fetchingVar = null;
}
} else {
shared.userVars.put("?", "");
}
StringBuilder rowBuilder = new StringBuilder();
String rowVal;
try {
for (String[] cells : rowData) {
if (cells.length == 1) {
rowVal = (cells[0] == null) ? nullRepToken : cells[0];
} else {
rowBuilder.setLength(0);
for (String s : cells) {
if (rowBuilder.length() > 0)
rowBuilder.append(dsvColDelim);
rowBuilder.append((s == null) ? nullRepToken : s);
}
rowVal = rowBuilder.toString();
}
shared.userVars.put("*ROW", rowVal);
if (vars != null) for (int i = 0; i < vars.length; i++)
if (cells[i] == null)
shared.userVars.remove(vars[i]);
else
shared.userVars.put(vars[i], cells[i]);
updateUserSettings();
Recursion origRecursed = recursed;
recursed = Recursion.FORROWS;
try {
scanpass(dupNesteds.dup());
} catch (ContinueException ce) {
String ceMessage = ce.getMessage();
if (ceMessage != null
&& !ceMessage.equals("forrows")) throw ce;
} finally {
recursed = origRecursed;
}
}
} catch (BreakException be) {
String beMessage = be.getMessage();
// Handle "forrows" and plain breaks (by doing nothing)
if (beMessage != null && !beMessage.equals("forrows")) throw be;
} catch (QuitNow qn) {
throw qn;
} catch (RuntimeException re) {
throw re; // Unrecoverable
} catch (Exception e) {
throw new BadSpecial(SqltoolRB.pl_block_fail.getString(), e);
} finally {
shared.userVars.remove("*ROW");
if (origVals != null) for (int i = 1; i < origVals.length; i++)
if (origVals[i] == null)
shared.userVars.remove(vars[i]);
else
shared.userVars.put(vars[i], origVals[i]);
updateUserSettings();
sqlExpandMode = null;
}
return;
}
if (tokens[0].equals("foreach")) {
Matcher foreachM = foreachPattern.matcher(
dereference(token.val, false));
if (!foreachM.matches())
throw new BadSpecial(
SqltoolRB.pl_malformat_specific.getString("foreach"));
if (foreachM.groupCount() != 2)
assert foreachM.groupCount() == 2:
"Internal assertion failed. "
+ "foreach pattern matched, but captured "
+ foreachM.groupCount() + " groups";
String varName = foreachM.group(1);
if (varName.indexOf(':') > -1)
throw new BadSpecial(SqltoolRB.plvar_nocolon.getString());
if (!varPattern.matcher(varName).matches())
errprintln(SqltoolRB.varname_warning.getString(varName));
String[] values = foreachM.group(2).split("\\s+", -1);
String origval = shared.userVars.get(varName);
try {
for (String val : values) {
// val may never be null
shared.userVars.put(varName, val);
updateUserSettings();
Recursion origRecursed = recursed;
recursed = Recursion.FOREACH;
try {
scanpass(token.nestedBlock.dup());
} catch (ContinueException ce) {
String ceMessage = ce.getMessage();
if (ceMessage != null
&& !ceMessage.equals("foreach")) throw ce;
} finally {
recursed = origRecursed;
}
}
} catch (BreakException be) {
String beMessage = be.getMessage();
// Handle "foreach" and plain breaks (by doing nothing)
if (beMessage != null && !beMessage.equals("foreach")) throw be;
} catch (QuitNow qn) {
throw qn;
} catch (RuntimeException re) {
throw re; // Unrecoverable
} catch (Exception e) {
throw new BadSpecial(SqltoolRB.pl_block_fail.getString(), e);
} finally {
if (origval == null) {
shared.userVars.remove(varName);
} else {
shared.userVars.put(varName, origval);
}
updateUserSettings();
sqlExpandMode = null;
}
return;
}
if (tokens[0].equals("if") || tokens[0].equals("while")) {
Matcher ifwhileM= ifwhilePattern.matcher(
dereference(token.val, false));
if (!ifwhileM.matches())
throw new BadSpecial(SqltoolRB.ifwhile_malformat.getString());
assert ifwhileM.groupCount() == 1:
"Internal assertion failed. "
+ "if/while pattern matched, but captured "
+ ifwhileM.groupCount() + " groups";
String[] values =
ifwhileM.group(1).replaceAll("!([a-zA-Z0-9*])", "! $1").
replaceAll("([a-zA-Z0-9*])!", "$1 !").split("\\s+", -1);
if (tokens[0].equals("if")) {
try {
// Provisionally 'else'. Will be nulled if it is not:
Token elseToken = (token.nestedBlock.size() < 1)
? null
: token.nestedBlock.get(
token.nestedBlock.size() - 1);
if (elseToken != null && (elseToken.type != Token.PL_TYPE ||
!elseToken.val.equals("else"))) elseToken = null;
//if (elseToken != null)
//token.nestedBlock.remove(token.nestedBlock.size() - 1);
Token recurseToken = eval(values) ? token : elseToken;
if (recurseToken != null) {
Recursion origRecursed = recursed;
recursed = Recursion.IF;
try {
scanpass(recurseToken.nestedBlock.dup());