Unverified 提交 4be14cbf authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1542 from katzyn/misc

Reduce GC pressure
无相关合并请求
......@@ -21,6 +21,14 @@ Change Log
<h2>Next Version (unreleased)</h2>
<ul>
<li>Issue #1534: Typo in message
</li>
<li>Issue #1527: Parser performance: Excessive use of regular expressions to validate column names
</li>
<li>PR #1543: MVStore assorted re-factorings
</li>
<li>PR #1538: Add support for newer Lucene versions without recompilation
</li>
<li>Issue #1536: CURRENT_TIMESTAMP result doesn't change under Transactions
</li>
<li>Issue #239: Consider supporting Lucene 5 indexes
......
......@@ -628,7 +628,8 @@ public final class Interval {
@Override
public String toString() {
return IntervalUtils.intervalToString(qualifier, negative, leading, remaining);
return IntervalUtils.appendInterval(new StringBuilder(), getQualifier(), negative, leading, remaining)
.toString();
}
}
......@@ -7,6 +7,7 @@ package org.h2.api;
import java.io.Serializable;
import org.h2.util.DateTimeUtils;
import org.h2.value.ValueTimestampTimeZone;
/**
* How we expose "TIMESTAMP WITH TIME ZONE" in our ResultSets.
......@@ -109,7 +110,9 @@ public class TimestampWithTimeZone implements Serializable, Cloneable {
@Override
public String toString() {
return DateTimeUtils.timestampTimeZoneToString(dateValue, timeNanos, timeZoneOffsetMins);
StringBuilder builder = new StringBuilder(ValueTimestampTimeZone.MAXIMUM_PRECISION);
DateTimeUtils.appendTimestampTimeZone(builder, dateValue, timeNanos, timeZoneOffsetMins);
return builder.toString();
}
@Override
......
......@@ -2687,9 +2687,14 @@ public class Parser {
}
private void setSQL(Prepared command, String start, int startIndex) {
String sql = StringUtils.trimSubstring(originalSQL, startIndex, lastParseIndex);
int endIndex = lastParseIndex;
String sql;
if (start != null) {
sql = start + " " + sql;
StringBuilder builder = new StringBuilder(start.length() + endIndex - startIndex + 1)
.append(start).append(' ');
sql = StringUtils.trimSubstring(builder, originalSQL, startIndex, endIndex).toString();
} else {
sql = StringUtils.trimSubstring(originalSQL, startIndex, endIndex);
}
command.setSQL(sql);
}
......@@ -2743,16 +2748,13 @@ public class Parser {
// special case: NOT NULL is not part of an expression (as in CREATE
// TABLE TEST(ID INT DEFAULT 0 NOT NULL))
int backup = parseIndex;
boolean not = false;
if (readIf(NOT)) {
not = true;
if (isToken(NULL)) {
// this really only works for NOT NULL!
parseIndex = backup;
currentToken = "NOT";
currentTokenType = NOT;
break;
}
boolean not = readIf(NOT);
if (not && isToken(NULL)) {
// this really only works for NOT NULL!
parseIndex = backup;
currentToken = "NOT";
currentTokenType = NOT;
break;
}
if (readIf(LIKE)) {
Expression b = readConcat();
......@@ -2841,6 +2843,9 @@ public class Parser {
Comparison.BIGGER_EQUAL, high, r);
r = new ConditionAndOr(ConditionAndOr.AND, condLow, condHigh);
} else {
if (not) {
throw getSyntaxError();
}
int compareType = getCompareType(currentTokenType);
if (compareType < 0) {
break;
......@@ -4333,9 +4338,12 @@ public class Parser {
}
i++;
}
currentToken = StringUtils.cache(sqlCommand.substring(
start, i));
currentTokenType = getTokenType(currentToken);
currentTokenType = ParserUtil.getSaveTokenType(sqlCommand, !identifiersToUpper, start, i, false);
if (currentTokenType == IDENTIFIER) {
currentToken = StringUtils.cache(sqlCommand.substring(start, i));
} else {
currentToken = TOKENS[currentTokenType];
}
parseIndex = i;
return;
case CHAR_QUOTED: {
......@@ -4452,8 +4460,7 @@ public class Parser {
}
currentToken = "'";
checkLiterals(true);
currentValue = ValueString.get(StringUtils.cache(result),
database.getMode().treatEmptyStringsAsNull);
currentValue = ValueString.get(result, database.getMode().treatEmptyStringsAsNull);
parseIndex = i;
currentTokenType = VALUE;
return;
......@@ -4466,8 +4473,7 @@ public class Parser {
String result = sqlCommand.substring(begin, i);
currentToken = "'";
checkLiterals(true);
currentValue = ValueString.get(StringUtils.cache(result),
database.getMode().treatEmptyStringsAsNull);
currentValue = ValueString.get(result, database.getMode().treatEmptyStringsAsNull);
parseIndex = i;
currentTokenType = VALUE;
return;
......@@ -4891,18 +4897,6 @@ public class Parser {
throw getSyntaxError();
}
private int getTokenType(String s) {
int len = s.length();
if (len == 0) {
throw getSyntaxError();
}
if (!identifiersToUpper) {
// if not yet converted to uppercase, do it now
s = StringUtils.toUpperEnglish(s);
}
return ParserUtil.getSaveTokenType(s, false);
}
private boolean isKeyword(String s) {
if (!identifiersToUpper) {
// if not yet converted to uppercase, do it now
......@@ -7713,6 +7707,24 @@ public class Parser {
return StringUtils.quoteIdentifier(s);
}
/**
* Add double quotes around an identifier if required and appends it to the
* specified string builder.
*
* @param builder string builder to append to
* @param s the identifier
* @return the specified builder
*/
public static StringBuilder quoteIdentifier(StringBuilder builder, String s) {
if (s == null) {
return builder.append("\"\"");
}
if (ParserUtil.isSimpleIdentifier(s)) {
return builder.append(s);
}
return StringUtils.quoteIdentifier(builder, s);
}
public void setLiteralsChecked(boolean literalsChecked) {
this.literalsChecked = literalsChecked;
}
......
......@@ -405,7 +405,7 @@ public abstract class Prepared {
for (Value v : values) {
buff.appendExceptFirst(", ");
if (v != null) {
buff.append(v.getSQL());
v.getSQL(buff.builder());
}
}
return buff.toString();
......@@ -418,14 +418,9 @@ public abstract class Prepared {
* @return the SQL snippet
*/
protected static String getSQL(Expression[] list) {
StatementBuilder buff = new StatementBuilder();
for (Expression e : list) {
buff.appendExceptFirst(", ");
if (e != null) {
buff.append(e.getSQL());
}
}
return buff.toString();
StringBuilder builder = new StringBuilder();
Expression.writeExpressions(builder, list);
return builder.toString();
}
/**
......
......@@ -74,7 +74,7 @@ public class CreateUser extends DefineCommand {
char[] passwordChars = pwd == null ? new char[0] : pwd.toCharArray();
byte[] userPasswordHash;
String userName = user.getName();
if (userName.length() == 0 && passwordChars.length == 0) {
if (userName.isEmpty() && passwordChars.length == 0) {
userPasswordHash = new byte[0];
} else {
userPasswordHash = SHA256.getKeyPasswordHash(userName, passwordChars);
......
......@@ -20,7 +20,6 @@ import org.h2.result.RowList;
import org.h2.table.PlanItem;
import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.util.StringUtils;
import org.h2.value.Value;
import org.h2.value.ValueNull;
......@@ -137,15 +136,15 @@ public class Delete extends Prepared {
@Override
public String getPlanSQL() {
StringBuilder buff = new StringBuilder();
buff.append("DELETE ");
buff.append("FROM ").append(targetTableFilter.getPlanSQL(false));
buff.append("DELETE FROM ");
targetTableFilter.getPlanSQL(buff, false);
if (condition != null) {
buff.append("\nWHERE ").append(StringUtils.unEnclose(
condition.getSQL()));
buff.append("\nWHERE ");
condition.getUnenclosedSQL(buff);
}
if (limitExpr != null) {
buff.append("\nLIMIT (").append(StringUtils.unEnclose(
limitExpr.getSQL())).append(')');
buff.append("\nLIMIT (");
limitExpr.getUnenclosedSQL(buff).append(')');
}
return buff.toString();
}
......
......@@ -303,7 +303,7 @@ public class Insert extends Prepared implements ResultTarget {
if (e == null) {
buff.append("DEFAULT");
} else {
buff.append(e.getSQL());
e.getSQL(buff.builder());
}
}
buff.append(')');
......@@ -421,7 +421,8 @@ public class Insert extends Prepared implements ResultTarget {
for (Column column : duplicateKeyAssignmentMap.keySet()) {
buff.appendExceptFirst(", ");
Expression ex = duplicateKeyAssignmentMap.get(column);
buff.append(column.getSQL()).append('=').append(ex.getSQL());
buff.append(column.getSQL()).append('=');
ex.getSQL(buff.builder());
}
buff.append(" WHERE ");
Index foundIndex = (Index) de.getSource();
......@@ -429,7 +430,7 @@ public class Insert extends Prepared implements ResultTarget {
throw DbException.getUnsupportedException(
"Unable to apply ON DUPLICATE KEY UPDATE, no index found!");
}
buff.append(prepareUpdateCondition(foundIndex, row).getSQL());
prepareUpdateCondition(foundIndex, row).getSQL(buff.builder());
String sql = buff.toString();
Update command = (Update) session.prepare(sql);
command.setUpdateToCurrentValuesReturnsZero(true);
......
......@@ -248,7 +248,7 @@ public class Merge extends Prepared {
if (e == null) {
buff.append("DEFAULT");
} else {
buff.append(e.getSQL());
e.getSQL(buff.builder());
}
}
buff.append(')');
......
......@@ -25,7 +25,6 @@ import org.h2.result.Row;
import org.h2.result.RowImpl;
import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.util.StatementBuilder;
import org.h2.util.Utils;
import org.h2.value.Value;
......@@ -343,10 +342,10 @@ public class MergeUsing extends Prepared {
@Override
public String getPlanSQL() {
StatementBuilder buff = new StatementBuilder("MERGE INTO ");
buff.append(targetTable.getSQL()).append('\n').append("USING ").append(query.getPlanSQL());
StringBuilder builder = new StringBuilder("MERGE INTO ");
builder.append(targetTable.getSQL()).append('\n').append("USING ").append(query.getPlanSQL());
// TODO add aliases and WHEN clauses to make plan SQL more like original SQL
return buff.toString();
return builder.toString();
}
@Override
......
......@@ -228,7 +228,7 @@ public class Replace extends Prepared {
if (e == null) {
buff.append("DEFAULT");
} else {
buff.append(e.getSQL());
e.getSQL(buff.builder());
}
}
buff.append(')');
......
......@@ -392,7 +392,7 @@ public class ScriptCommand extends ScriptBase {
buff.append(table.getSQL()).append('(');
for (Column col : columns) {
buff.appendExceptFirst(", ");
buff.append(Parser.quoteIdentifier(col.getName()));
Parser.quoteIdentifier(buff.builder(), col.getName());
}
buff.append(") VALUES");
if (!simple) {
......@@ -422,10 +422,10 @@ public class ScriptCommand extends ScriptBase {
id = writeLobStream(v);
buff.append("SYSTEM_COMBINE_BLOB(").append(id).append(')');
} else {
buff.append(v.getSQL());
v.getSQL(buff.builder());
}
} else {
buff.append(v.getSQL());
v.getSQL(buff.builder());
}
}
buff.append(')');
......@@ -471,7 +471,7 @@ public class ScriptCommand extends ScriptBase {
if (len <= 0) {
break;
}
buff.append(StringUtils.convertBytesToHex(bytes, len)).append("')");
StringUtils.convertBytesToHex(buff, bytes, len).append("')");
String sql = buff.toString();
add(sql, true);
}
......@@ -490,7 +490,7 @@ public class ScriptCommand extends ScriptBase {
if (len == 0) {
break;
}
buff.append(StringUtils.quoteStringSQL(new String(chars, 0, len))).
StringUtils.quoteStringSQL(buff, new String(chars, 0, len)).
append(", NULL)");
String sql = buff.toString();
add(sql, true);
......
......@@ -1308,7 +1308,8 @@ public class Select extends Query {
// views.
} else {
buff.append("WITH RECURSIVE ")
.append(t.getSchema().getSQL()).append('.').append(Parser.quoteIdentifier(t.getName()))
.append(t.getSchema().getSQL()).append('.');
Parser.quoteIdentifier(buff.builder(), t.getName())
.append('(');
buff.resetCount();
for (Column c : t.getColumns()) {
......@@ -1327,7 +1328,7 @@ public class Select extends Query {
buff.append(" ON(");
for (Expression distinctExpression: distinctExpressions) {
buff.appendExceptFirst(", ");
buff.append(distinctExpression.getSQL());
distinctExpression.getSQL(buff.builder());
}
buff.append(')');
buff.resetCount();
......@@ -1336,7 +1337,7 @@ public class Select extends Query {
for (int i = 0; i < visibleColumnCount; i++) {
buff.appendExceptFirst(",");
buff.append('\n');
buff.append(StringUtils.indent(exprList[i].getSQL(), 4, false));
StringUtils.indent(buff.builder(), exprList[i].getSQL(), 4, false);
}
buff.append("\nFROM ");
TableFilter filter = topTableFilter;
......@@ -1345,7 +1346,7 @@ public class Select extends Query {
int i = 0;
do {
buff.appendExceptFirst("\n");
buff.append(filter.getPlanSQL(i++ > 0));
filter.getPlanSQL(buff.builder(), i++ > 0);
filter = filter.getJoin();
} while (filter != null);
} else {
......@@ -1354,14 +1355,14 @@ public class Select extends Query {
for (TableFilter f : topFilters) {
do {
buff.appendExceptFirst("\n");
buff.append(f.getPlanSQL(i++ > 0));
f.getPlanSQL(buff.builder(), i++ > 0);
f = f.getJoin();
} while (f != null);
}
}
if (condition != null) {
buff.append("\nWHERE ").append(
StringUtils.unEnclose(condition.getSQL()));
buff.append("\nWHERE ");
condition.getUnenclosedSQL(buff.builder());
}
if (groupIndex != null) {
buff.append("\nGROUP BY ");
......@@ -1370,7 +1371,7 @@ public class Select extends Query {
Expression g = exprList[gi];
g = g.getNonAliasExpression();
buff.appendExceptFirst(", ");
buff.append(StringUtils.unEnclose(g.getSQL()));
g.getUnenclosedSQL(buff.builder());
}
}
if (group != null) {
......@@ -1378,7 +1379,7 @@ public class Select extends Query {
buff.resetCount();
for (Expression g : group) {
buff.appendExceptFirst(", ");
buff.append(StringUtils.unEnclose(g.getSQL()));
g.getUnenclosedSQL(buff.builder());
}
}
if (having != null) {
......@@ -1386,12 +1387,12 @@ public class Select extends Query {
// in this case the query is not run directly, just getPlanSQL is
// called
Expression h = having;
buff.append("\nHAVING ").append(
StringUtils.unEnclose(h.getSQL()));
buff.append("\nHAVING ");
h.getUnenclosedSQL(buff.builder());
} else if (havingIndex >= 0) {
Expression h = exprList[havingIndex];
buff.append("\nHAVING ").append(
StringUtils.unEnclose(h.getSQL()));
buff.append("\nHAVING ");
h.getUnenclosedSQL(buff.builder());
}
if (sort != null) {
buff.append("\nORDER BY ").append(
......@@ -1407,8 +1408,8 @@ public class Select extends Query {
}
appendLimitToSQL(buff.builder());
if (sampleSizeExpr != null) {
buff.append("\nSAMPLE_SIZE ").append(
StringUtils.unEnclose(sampleSizeExpr.getSQL()));
buff.append("\nSAMPLE_SIZE ");
sampleSizeExpr.getUnenclosedSQL(buff.builder());
}
if (isForUpdate) {
buff.append("\nFOR UPDATE");
......
......@@ -33,9 +33,10 @@ public class SelectOrderBy {
public String getSQL() {
StringBuilder buff = new StringBuilder();
if (expression != null) {
buff.append('=').append(expression.getSQL());
buff.append('=');
expression.getSQL(buff);
} else {
buff.append(columnIndexExpr.getSQL());
columnIndexExpr.getSQL(buff);
}
SortOrder.typeToString(buff, sortType);
return buff.toString();
......
......@@ -28,7 +28,6 @@ import org.h2.table.ColumnResolver;
import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.util.ColumnNamer;
import org.h2.util.StringUtils;
import org.h2.value.Value;
import org.h2.value.ValueInt;
import org.h2.value.ValueNull;
......@@ -429,8 +428,8 @@ public class SelectUnion extends Query {
}
appendLimitToSQL(buff);
if (sampleSizeExpr != null) {
buff.append("\nSAMPLE_SIZE ").append(
StringUtils.unEnclose(sampleSizeExpr.getSQL()));
buff.append("\nSAMPLE_SIZE ");
sampleSizeExpr.getUnenclosedSQL(buff);
}
if (isForUpdate) {
buff.append("\nFOR UPDATE");
......
......@@ -27,8 +27,6 @@ import org.h2.table.Column;
import org.h2.table.PlanItem;
import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils;
import org.h2.util.Utils;
import org.h2.value.Value;
import org.h2.value.ValueNull;
......@@ -217,21 +215,25 @@ public class Update extends Prepared {
@Override
public String getPlanSQL() {
StatementBuilder buff = new StatementBuilder("UPDATE ");
buff.append(targetTableFilter.getPlanSQL(false)).append("\nSET\n ");
for (Column c : columns) {
Expression e = expressionMap.get(c);
buff.appendExceptFirst(",\n ");
buff.append(c.getName()).append(" = ").append(e.getSQL());
StringBuilder builder = new StringBuilder("UPDATE ");
targetTableFilter.getPlanSQL(builder, false).append("\nSET\n ");
for (int i = 0, size = columns.size(); i < size; i++) {
if (i > 0) {
builder.append(",\n ");
}
Column c = columns.get(i);
builder.append(c.getName()).append(" = ");
expressionMap.get(c).getSQL(builder);
}
if (condition != null) {
buff.append("\nWHERE ").append(StringUtils.unEnclose(condition.getSQL()));
builder.append("\nWHERE ");
condition.getUnenclosedSQL(builder);
}
if (limitExpr != null) {
buff.append("\nLIMIT ").append(
StringUtils.unEnclose(limitExpr.getSQL()));
builder.append("\nLIMIT ");
limitExpr.getUnenclosedSQL(builder);
}
return buff.toString();
return builder.toString();
}
@Override
......
......@@ -56,15 +56,18 @@ public class ConstraintCheck extends Constraint {
}
buff.append(quotedName);
if (comment != null) {
buff.append(" COMMENT ").append(StringUtils.quoteStringSQL(comment));
buff.append(" COMMENT ");
StringUtils.quoteStringSQL(buff, comment);
}
buff.append(" CHECK").append(StringUtils.enclose(expr.getSQL()))
.append(" NOCHECK");
buff.append(" CHECK(");
expr.getUnenclosedSQL(buff).append(") NOCHECK");
return buff.toString();
}
private String getShortDescription() {
return getName() + ": " + expr.getSQL();
StringBuilder builder = new StringBuilder().append(getName()).append(": ");
expr.getSQL(builder);
return builder.toString();
}
@Override
......@@ -140,8 +143,11 @@ public class ConstraintCheck extends Constraint {
// don't check at startup
return;
}
String sql = "SELECT 1 FROM " + filter.getTable().getSQL() +
" WHERE NOT(" + expr.getSQL() + ")";
StringBuilder builder = new StringBuilder().append("SELECT 1 FROM ")
.append(filter.getTable().getSQL())
.append(" WHERE NOT(");
expr.getSQL(builder).append(')');
String sql = builder.toString();
ResultInterface r = session.prepare(sql).query(1);
if (r.next()) {
throw DbException.get(ErrorCode.CHECK_CONSTRAINT_VIOLATED_1, getName());
......
......@@ -87,7 +87,8 @@ public class ConstraintReferential extends Constraint {
}
buff.append(quotedName);
if (comment != null) {
buff.append(" COMMENT ").append(StringUtils.quoteStringSQL(comment));
buff.append(" COMMENT ");
StringUtils.quoteStringSQL(buff.builder(), comment);
}
IndexColumn[] cols = columns;
IndexColumn[] refCols = refColumns;
......@@ -566,8 +567,8 @@ public class ConstraintReferential extends Constraint {
buff.append("UPDATE ").append(table.getSQL()).append(" SET ");
buff.resetCount();
for (IndexColumn c : columns) {
buff.appendExceptFirst(" , ");
buff.append(Parser.quoteIdentifier(c.column.getName())).append("=?");
buff.appendExceptFirst(", ");
Parser.quoteIdentifier(buff.builder(), c.column.getName()).append("=?");
}
}
......@@ -576,7 +577,7 @@ public class ConstraintReferential extends Constraint {
buff.resetCount();
for (IndexColumn c : columns) {
buff.appendExceptFirst(" AND ");
buff.append(Parser.quoteIdentifier(c.column.getName())).append("=?");
Parser.quoteIdentifier(buff.builder(), c.column.getName()).append("=?");
}
}
......
......@@ -52,12 +52,13 @@ public class ConstraintUnique extends Constraint {
}
buff.append(quotedName);
if (comment != null) {
buff.append(" COMMENT ").append(StringUtils.quoteStringSQL(comment));
buff.append(" COMMENT ");
StringUtils.quoteStringSQL(buff.builder(), comment);
}
buff.append(' ').append(getConstraintType().getSqlName()).append('(');
for (IndexColumn c : columns) {
buff.appendExceptFirst(", ");
buff.append(Parser.quoteIdentifier(c.column.getName()));
Parser.quoteIdentifier(buff.builder(), c.column.getName());
}
buff.append(')');
if (internalIndex && indexOwner && forTable == this.table) {
......
......@@ -74,7 +74,7 @@ public class Comment extends DbObjectBase {
if (commentText == null) {
buff.append("NULL");
} else {
buff.append(StringUtils.quoteStringSQL(commentText));
StringUtils.quoteStringSQL(buff, commentText);
}
return buff.toString();
}
......
......@@ -252,7 +252,7 @@ public class ConnectionInfo implements Cloneable {
url = url.substring(0, idx);
String[] list = StringUtils.arraySplit(settings, ';', false);
for (String setting : list) {
if (setting.length() == 0) {
if (setting.isEmpty()) {
continue;
}
int equal = setting.indexOf('=');
......@@ -326,7 +326,7 @@ public class ConnectionInfo implements Cloneable {
if (passwordHash) {
return StringUtils.convertHexToBytes(new String(password));
}
if (userName.length() == 0 && password.length == 0) {
if (userName.isEmpty() && password.length == 0) {
return new byte[0];
}
return SHA256.getKeyPasswordHash(userName, password);
......@@ -643,7 +643,7 @@ public class ConnectionInfo implements Cloneable {
private static String remapURL(String url) {
String urlMap = SysProperties.URL_MAP;
if (urlMap != null && urlMap.length() > 0) {
if (urlMap != null && !urlMap.isEmpty()) {
try {
SortedProperties prop;
prop = SortedProperties.loadProperties(urlMap);
......@@ -653,7 +653,7 @@ public class ConnectionInfo implements Cloneable {
prop.store(urlMap);
} else {
url2 = url2.trim();
if (url2.length() > 0) {
if (!url2.isEmpty()) {
return url2;
}
}
......
......@@ -642,7 +642,7 @@ public class Database implements DataHandler {
n = tokenizer.nextToken();
}
}
if (n == null || n.length() == 0) {
if (n == null || n.isEmpty()) {
n = "unnamed";
}
return dbSettings.databaseToUpper ? StringUtils.toUpperEnglish(n) : n;
......@@ -2274,7 +2274,7 @@ public class Database implements DataHandler {
}
public void setEventListenerClass(String className) {
if (className == null || className.length() == 0) {
if (className == null || className.isEmpty()) {
eventListener = null;
} else {
try {
......
......@@ -223,10 +223,11 @@ public class FunctionAlias extends SchemaObjectBase {
buff.append(" NOBUFFER");
}
if (source != null) {
buff.append(" AS ").append(StringUtils.quoteStringSQL(source));
buff.append(" AS ");
StringUtils.quoteStringSQL(buff, source);
} else {
buff.append(" FOR ").append(Parser.quoteIdentifier(
className + "." + methodName));
buff.append(" FOR ");
Parser.quoteIdentifier(buff, className + "." + methodName);
}
return buff.toString();
}
......
......@@ -159,13 +159,14 @@ public class User extends RightOwner {
StringBuilder buff = new StringBuilder("CREATE USER IF NOT EXISTS ");
buff.append(getSQL());
if (comment != null) {
buff.append(" COMMENT ").append(StringUtils.quoteStringSQL(comment));
buff.append(" COMMENT ");
StringUtils.quoteStringSQL(buff, comment);
}
if (password) {
buff.append(" SALT '").
append(StringUtils.convertBytesToHex(salt)).
append("' HASH '").
append(StringUtils.convertBytesToHex(passwordHash)).
buff.append(" SALT '");
StringUtils.convertBytesToHex(buff, salt).
append("' HASH '");
StringUtils.convertBytesToHex(buff, passwordHash).
append('\'');
} else {
buff.append(" PASSWORD ''");
......
......@@ -78,8 +78,9 @@ public class Alias extends Expression {
}
@Override
public String getSQL() {
return expr.getSQL() + " AS " + Parser.quoteIdentifier(alias);
public StringBuilder getSQL(StringBuilder builder) {
expr.getSQL(builder).append(" AS ");
return Parser.quoteIdentifier(builder, alias);
}
@Override
......
......@@ -68,10 +68,12 @@ public class BinaryOperation extends Expression {
}
@Override
public String getSQL() {
public StringBuilder getSQL(StringBuilder builder) {
// don't remove the space, otherwise it might end up some thing like
// --1 which is a line remark
return '(' + left.getSQL() + ' ' + getOperationToken() + ' ' + right.getSQL() + ')';
builder.append('(');
left.getSQL(builder).append(' ').append(getOperationToken()).append(' ');
return right.getSQL(builder).append(')');
}
private String getOperationToken() {
......
......@@ -72,21 +72,24 @@ public class CompareLike extends Condition {
}
private static Character getEscapeChar(String s) {
return s == null || s.length() == 0 ? null : s.charAt(0);
return s == null || s.isEmpty() ? null : s.charAt(0);
}
@Override
public String getSQL() {
String sql;
public StringBuilder getSQL(StringBuilder builder) {
builder.append('(');
if (regexp) {
sql = left.getSQL() + " REGEXP " + right.getSQL();
left.getSQL(builder).append(" REGEXP ");
right.getSQL(builder);
} else {
sql = left.getSQL() + " LIKE " + right.getSQL();
left.getSQL(builder).append(" LIKE ");
right.getSQL(builder);
if (escape != null) {
sql += " ESCAPE " + escape.getSQL();
builder.append(" ESCAPE ");
escape.getSQL(builder);
}
}
return "(" + sql + ")";
return builder.append(')');
}
@Override
......
......@@ -126,23 +126,25 @@ public class Comparison extends Condition {
}
@Override
public String getSQL() {
String sql;
public StringBuilder getSQL(StringBuilder builder) {
builder.append('(');
switch (compareType) {
case IS_NULL:
sql = left.getSQL() + " IS NULL";
left.getSQL(builder).append(" IS NULL");
break;
case IS_NOT_NULL:
sql = left.getSQL() + " IS NOT NULL";
left.getSQL(builder).append(" IS NOT NULL");
break;
case SPATIAL_INTERSECTS:
sql = "INTERSECTS(" + left.getSQL() + ", " + right.getSQL() + ")";
builder.append("INTERSECTS(");
left.getSQL(builder).append(", ");
right.getSQL(builder).append(')');
break;
default:
sql = left.getSQL() + " " + getCompareOperator(compareType) +
" " + right.getSQL();
left.getSQL(builder).append(' ').append(getCompareOperator(compareType)).append(' ');
right.getSQL(builder);
}
return "(" + sql + ")";
return builder.append(')');
}
/**
......
......@@ -42,19 +42,20 @@ public class ConditionAndOr extends Condition {
}
@Override
public String getSQL() {
String sql;
public StringBuilder getSQL(StringBuilder builder) {
builder.append('(');
left.getSQL(builder);
switch (andOrType) {
case AND:
sql = left.getSQL() + "\n AND " + right.getSQL();
builder.append("\n AND ");
break;
case OR:
sql = left.getSQL() + "\n OR " + right.getSQL();
builder.append("\n OR ");
break;
default:
throw DbException.throwInternalError("andOrType=" + andOrType);
}
return "(" + sql + ")";
return right.getSQL(builder).append(')');
}
@Override
......
......@@ -41,8 +41,9 @@ public class ConditionExists extends Condition {
}
@Override
public String getSQL() {
return "EXISTS(\n" + StringUtils.indent(query.getPlanSQL(), 4, false) + ")";
public StringBuilder getSQL(StringBuilder builder) {
builder.append("EXISTS(\n");
return StringUtils.indent(builder, query.getPlanSQL(), 4, false).append(')');
}
@Override
......
......@@ -11,7 +11,6 @@ import org.h2.engine.Session;
import org.h2.index.IndexCondition;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.util.StatementBuilder;
import org.h2.value.Value;
import org.h2.value.ValueBoolean;
import org.h2.value.ValueNull;
......@@ -152,14 +151,11 @@ public class ConditionIn extends Condition {
}
@Override
public String getSQL() {
StatementBuilder buff = new StatementBuilder("(");
buff.append(left.getSQL()).append(" IN(");
for (Expression e : valueList) {
buff.appendExceptFirst(", ");
buff.append(e.getSQL());
}
return buff.append("))").toString();
public StringBuilder getSQL(StringBuilder builder) {
builder.append('(');
left.getSQL(builder).append(" IN(");
writeExpressions(builder, valueList);
return builder.append("))");
}
@Override
......
......@@ -15,7 +15,6 @@ import org.h2.index.IndexCondition;
import org.h2.message.DbException;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.util.StatementBuilder;
import org.h2.value.ExtTypeInfo;
import org.h2.value.Value;
import org.h2.value.ValueBoolean;
......@@ -114,14 +113,11 @@ public class ConditionInConstantSet extends Condition {
}
@Override
public String getSQL() {
StatementBuilder buff = new StatementBuilder("(");
buff.append(left.getSQL()).append(" IN(");
for (Expression e : valueList) {
buff.appendExceptFirst(", ");
buff.append(e.getSQL());
}
return buff.append("))").toString();
public StringBuilder getSQL(StringBuilder builder) {
builder.append('(');
left.getSQL(builder).append(" IN(");
writeExpressions(builder, valueList);
return builder.append("))");
}
@Override
......
......@@ -140,8 +140,10 @@ public class ConditionInParameter extends Condition {
}
@Override
public String getSQL() {
return '(' + left.getSQL() + " = ANY(" + parameter.getSQL() + "))";
public StringBuilder getSQL(StringBuilder builder) {
builder.append('(');
left.getSQL(builder).append(" = ANY(");
return parameter.getSQL(builder).append("))");
}
@Override
......
......@@ -129,23 +129,22 @@ public class ConditionInSelect extends Condition {
}
@Override
public String getSQL() {
StringBuilder buff = new StringBuilder();
buff.append('(').append(left.getSQL()).append(' ');
public StringBuilder getSQL(StringBuilder builder) {
builder.append('(');
left.getSQL(builder).append(' ');
if (all) {
buff.append(Comparison.getCompareOperator(compareType)).
builder.append(Comparison.getCompareOperator(compareType)).
append(" ALL");
} else {
if (compareType == Comparison.EQUAL) {
buff.append("IN");
builder.append("IN");
} else {
buff.append(Comparison.getCompareOperator(compareType)).
builder.append(Comparison.getCompareOperator(compareType)).
append(" ANY");
}
}
buff.append("(\n").append(StringUtils.indent(query.getPlanSQL(), 4, false)).
append("))");
return buff.toString();
builder.append("(\n");
return StringUtils.indent(builder, query.getPlanSQL(), 4, false).append("))");
}
@Override
......
......@@ -65,8 +65,9 @@ public class ConditionNot extends Condition {
}
@Override
public String getSQL() {
return "(NOT " + condition.getSQL() + ")";
public StringBuilder getSQL(StringBuilder builder) {
builder.append("(NOT ");
return condition.getSQL(builder).append(')');
}
@Override
......
......@@ -5,13 +5,14 @@
*/
package org.h2.expression;
import java.util.List;
import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.result.ResultInterface;
import org.h2.table.Column;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.util.StringUtils;
import org.h2.value.Value;
import org.h2.value.ValueArray;
......@@ -39,6 +40,24 @@ public abstract class Expression {
private boolean addedToFilter;
public static void writeExpressions(StringBuilder builder, List<? extends Expression> expressions) {
for (int i = 0, length = expressions.size(); i < length; i++) {
if (i > 0) {
builder.append(", ");
}
expressions.get(i).getSQL(builder);
}
}
public static void writeExpressions(StringBuilder builder, Expression[] expressions) {
for (int i = 0, length = expressions.length; i < length; i++) {
if (i > 0) {
builder.append(", ");
}
expressions[i].getSQL(builder);
}
}
/**
* Return the resulting value for the current row.
*
......@@ -110,7 +129,39 @@ public abstract class Expression {
*
* @return the SQL statement
*/
public abstract String getSQL();
public String getSQL() {
return getSQL(new StringBuilder()).toString();
}
/**
* Appends the SQL statement of this expression to the specified builder.
* This may not always be the original SQL statement, specially after
* optimization.
*
* @param builder
* string builder
* @return the specified string builder
*/
public abstract StringBuilder getSQL(StringBuilder builder);
/**
* Appends the SQL statement of this expression to the specified builder.
* This may not always be the original SQL statement, specially after
* optimization. Enclosing '(' and ')' are removed.
*
* @param builder
* string builder
* @return the specified string builder
*/
public StringBuilder getUnenclosedSQL(StringBuilder builder) {
int first = builder.length();
int last = getSQL(builder).length() - 1;
if (last > first && builder.charAt(first) == '(' && builder.charAt(last) == ')') {
builder.setLength(last);
builder.deleteCharAt(first);
}
return builder;
}
/**
* Update an aggregate value. This method is called at statement execution
......@@ -268,7 +319,7 @@ public abstract class Expression {
* @return the alias name
*/
public String getAlias() {
return StringUtils.unEnclose(getSQL());
return getUnenclosedSQL(new StringBuilder()).toString();
}
/**
......
......@@ -55,23 +55,32 @@ public class ExpressionColumn extends Expression {
}
@Override
public String getSQL() {
String sql;
public StringBuilder getSQL(StringBuilder builder) {
boolean quote = database.getSettings().databaseToUpper;
if (column != null) {
sql = column.getSQL();
} else {
sql = quote ? Parser.quoteIdentifier(columnName) : columnName;
if (schemaName != null) {
if (quote) {
Parser.quoteIdentifier(builder, schemaName);
} else {
builder.append(schemaName);
}
builder.append('.');
}
if (tableAlias != null) {
String a = quote ? Parser.quoteIdentifier(tableAlias) : tableAlias;
sql = a + "." + sql;
if (quote) {
Parser.quoteIdentifier(builder, tableAlias);
} else {
builder.append(tableAlias);
}
builder.append('.');
}
if (schemaName != null) {
String s = quote ? Parser.quoteIdentifier(schemaName) : schemaName;
sql = s + "." + sql;
if (column != null) {
builder.append(column.getSQL());
} else if (quote) {
Parser.quoteIdentifier(builder, columnName);
} else {
builder.append(columnName);
}
return sql;
return builder;
}
public TableFilter getTableFilter() {
......
......@@ -9,7 +9,6 @@ import org.h2.engine.Session;
import org.h2.table.Column;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.util.StatementBuilder;
import org.h2.value.Value;
import org.h2.value.ValueArray;
......@@ -85,16 +84,13 @@ public class ExpressionList extends Expression {
}
@Override
public String getSQL() {
StatementBuilder buff = new StatementBuilder("(");
for (Expression e: list) {
buff.appendExceptFirst(", ");
buff.append(e.getSQL());
}
public StringBuilder getSQL(StringBuilder builder) {
builder.append('(');
writeExpressions(builder, list);
if (list.length == 1) {
buff.append(',');
builder.append(',');
}
return buff.append(')').toString();
return builder.append(')');
}
@Override
......
......@@ -50,7 +50,6 @@ import org.h2.util.DateTimeUtils;
import org.h2.util.IOUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.MathUtils;
import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils;
import org.h2.util.ToChar;
import org.h2.util.ToDateParser;
......@@ -682,7 +681,7 @@ public class Function extends Expression implements FunctionCall {
// string
case ASCII: {
String s = v0.getString();
if (s.length() == 0) {
if (s.isEmpty()) {
result = ValueNull.INSTANCE;
} else {
result = ValueInt.get(s.charAt(0));
......@@ -2582,36 +2581,41 @@ public class Function extends Expression implements FunctionCall {
}
@Override
public String getSQL() {
StatementBuilder buff = new StatementBuilder(info.name);
public StringBuilder getSQL(StringBuilder builder) {
builder.append(info.name);
if (info.type == CASE) {
if (args[0] != null) {
buff.append(' ').append(args[0].getSQL());
builder.append(' ');
args[0].getSQL(builder);
}
for (int i = 1, len = args.length - 1; i < len; i += 2) {
buff.append(" WHEN ").append(args[i].getSQL());
buff.append(" THEN ").append(args[i + 1].getSQL());
builder.append(" WHEN ");
args[i].getSQL(builder);
builder.append(" THEN ");
args[i + 1].getSQL(builder);
}
if (args.length % 2 == 0) {
buff.append(" ELSE ").append(args[args.length - 1].getSQL());
builder.append(" ELSE ");
args[args.length - 1].getSQL(builder);
}
return buff.append(" END").toString();
return builder.append(" END");
}
buff.append('(');
builder.append('(');
switch (info.type) {
case CAST: {
buff.append(args[0].getSQL()).append(" AS ").
args[0].getSQL(builder).append(" AS ").
append(new Column(null, dataType, precision,
scale, displaySize, extTypeInfo).getCreateSQL());
break;
}
case CONVERT: {
if (database.getMode().swapConvertFunctionParameters) {
buff.append(new Column(null, dataType, precision,
builder.append(new Column(null, dataType, precision,
scale, displaySize).getCreateSQL()).
append(',').append(args[0].getSQL());
append(',');
args[0].getSQL(builder);
} else {
buff.append(args[0].getSQL()).append(',').
args[0].getSQL(builder).append(',').
append(new Column(null, dataType, precision,
scale, displaySize).getCreateSQL());
}
......@@ -2619,17 +2623,14 @@ public class Function extends Expression implements FunctionCall {
}
case EXTRACT: {
ValueString v = (ValueString) ((ValueExpression) args[0]).getValue(null);
buff.append(v.getString()).append(" FROM ").append(args[1].getSQL());
builder.append(v.getString()).append(" FROM ");
args[1].getSQL(builder);
break;
}
default: {
for (Expression e : args) {
buff.appendExceptFirst(", ");
buff.append(e.getSQL());
}
}
default:
writeExpressions(builder, args);
}
return buff.append(')').toString();
return builder.append(')');
}
@Override
......@@ -2703,19 +2704,17 @@ public class Function extends Expression implements FunctionCall {
String fieldDelimiter, String escapeCharacter) {
if (fieldSeparator != null) {
csv.setFieldSeparatorWrite(fieldSeparator);
if (fieldSeparator.length() > 0) {
if (!fieldSeparator.isEmpty()) {
char fs = fieldSeparator.charAt(0);
csv.setFieldSeparatorRead(fs);
}
}
if (fieldDelimiter != null) {
char fd = fieldDelimiter.length() == 0 ?
0 : fieldDelimiter.charAt(0);
char fd = fieldDelimiter.isEmpty() ? 0 : fieldDelimiter.charAt(0);
csv.setFieldDelimiter(fd);
}
if (escapeCharacter != null) {
char ec = escapeCharacter.length() == 0 ?
0 : escapeCharacter.charAt(0);
char ec = escapeCharacter.isEmpty() ? 0 : escapeCharacter.charAt(0);
csv.setEscapeCharacter(ec);
}
}
......
......@@ -113,8 +113,10 @@ public class IntervalOperation extends Expression {
}
@Override
public String getSQL() {
return '(' + left.getSQL() + ' ' + getOperationToken() + ' ' + right.getSQL() + ')';
public StringBuilder getSQL(StringBuilder builder) {
builder.append('(');
left.getSQL(builder).append(' ').append(getOperationToken()).append(' ');
return right.getSQL(builder).append(')');
}
private char getOperationToken() {
......
......@@ -11,7 +11,6 @@ import org.h2.engine.FunctionAlias;
import org.h2.engine.Session;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.util.StatementBuilder;
import org.h2.value.DataType;
import org.h2.value.Value;
import org.h2.value.ValueArray;
......@@ -89,21 +88,15 @@ public class JavaFunction extends Expression implements FunctionCall {
}
@Override
public String getSQL() {
StatementBuilder buff = new StatementBuilder();
public StringBuilder getSQL(StringBuilder builder) {
// TODO always append the schema once FUNCTIONS_IN_SCHEMA is enabled
if (functionAlias.getDatabase().getSettings().functionsInSchema ||
!functionAlias.getSchema().getName().equals(Constants.SCHEMA_MAIN)) {
buff.append(
Parser.quoteIdentifier(functionAlias.getSchema().getName()))
.append('.');
Parser.quoteIdentifier(builder, functionAlias.getSchema().getName()).append('.');
}
buff.append(Parser.quoteIdentifier(functionAlias.getName())).append('(');
for (Expression e : args) {
buff.appendExceptFirst(", ");
buff.append(e.getSQL());
}
return buff.append(')').toString();
Parser.quoteIdentifier(builder, functionAlias.getName()).append('(');
writeExpressions(builder, this.args);
return builder.append(')');
}
@Override
......
......@@ -30,8 +30,8 @@ public class Parameter extends Expression implements ParameterInterface {
}
@Override
public String getSQL() {
return "?" + (index + 1);
public StringBuilder getSQL(StringBuilder builder) {
return builder.append('?').append(index + 1);
}
@Override
......
......@@ -72,6 +72,11 @@ public class Rownum extends Expression {
return "ROWNUM()";
}
@Override
public StringBuilder getSQL(StringBuilder builder) {
return builder.append("ROWNUM()");
}
@Override
public void updateAggregate(Session session, int stage) {
// nothing to do
......
......@@ -67,8 +67,9 @@ public class SequenceValue extends Expression {
}
@Override
public String getSQL() {
return "(NEXT VALUE FOR " + sequence.getSQL() +")";
public StringBuilder getSQL(StringBuilder builder) {
builder.append("(NEXT VALUE FOR ");
return builder.append(sequence.getSQL()).append(')');
}
@Override
......
......@@ -89,8 +89,8 @@ public class Subquery extends Expression {
}
@Override
public String getSQL() {
return "(" + query.getPlanSQL() + ")";
public StringBuilder getSQL(StringBuilder builder) {
return builder.append('(').append(query.getPlanSQL()).append(')');
}
@Override
......
......@@ -13,7 +13,6 @@ import org.h2.engine.Session;
import org.h2.message.DbException;
import org.h2.result.LocalResult;
import org.h2.table.Column;
import org.h2.util.StatementBuilder;
import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueNull;
......@@ -46,15 +45,16 @@ public class TableFunction extends Function {
}
@Override
public String getSQL() {
StatementBuilder buff = new StatementBuilder(getName());
buff.append('(');
int i = 0;
for (Expression e : args) {
buff.appendExceptFirst(", ");
buff.append(columnList[i++].getCreateSQL()).append('=').append(e.getSQL());
public StringBuilder getSQL(StringBuilder builder) {
builder.append(getName()).append('(');
for (int i = 0; i < args.length; i++) {
if (i > 0) {
builder.append(", ");
}
builder.append(columnList[i].getCreateSQL()).append('=');
args[i].getSQL(builder);
}
return buff.append(')').toString();
return builder.append(')');
}
......
......@@ -24,10 +24,11 @@ public class UnaryOperation extends Expression {
}
@Override
public String getSQL() {
public StringBuilder getSQL(StringBuilder builder) {
// don't remove the space, otherwise it might end up some thing like
// --1 which is a line remark
return "(- " + arg.getSQL() + ')';
builder.append("(- ");
return arg.getSQL(builder).append(')');
}
@Override
......
......@@ -135,11 +135,13 @@ public class ValueExpression extends Expression {
}
@Override
public String getSQL() {
public StringBuilder getSQL(StringBuilder builder) {
if (this == DEFAULT) {
return "DEFAULT";
builder.append("DEFAULT");
} else {
value.getSQL(builder);
}
return value.getSQL();
return builder;
}
@Override
......
......@@ -41,8 +41,9 @@ public class Variable extends Expression {
}
@Override
public String getSQL() {
return "@" + Parser.quoteIdentifier(name);
public StringBuilder getSQL(StringBuilder builder) {
builder.append('@');
return Parser.quoteIdentifier(builder, name);
}
@Override
......
......@@ -116,24 +116,17 @@ public class Wildcard extends Expression {
}
@Override
public String getSQL() {
StringBuilder builder = new StringBuilder();
public StringBuilder getSQL(StringBuilder builder) {
if (table != null) {
builder.append(StringUtils.quoteIdentifier(table)).append('.');
StringUtils.quoteIdentifier(builder, table).append('.');
}
builder.append('*');
if (exceptColumns != null) {
builder.append(" EXCEPT (");
for (int i = 0; i < exceptColumns.size(); i++) {
if (i > 0) {
builder.append(", ");
}
ExpressionColumn ec = exceptColumns.get(i);
builder.append(ec.getSQL());
}
writeExpressions(builder, exceptColumns);
builder.append(')');
}
return builder.toString();
return builder;
}
@Override
......
......@@ -159,7 +159,8 @@ public abstract class AbstractAggregate extends DataAnalysisOperation {
@Override
protected StringBuilder appendTailConditions(StringBuilder builder) {
if (filterCondition != null) {
builder.append(" FILTER (WHERE ").append(filterCondition.getSQL()).append(')');
builder.append(" FILTER (WHERE ");
filterCondition.getSQL(builder).append(')');
}
return super.appendTailConditions(builder);
}
......
......@@ -30,7 +30,6 @@ import org.h2.table.ColumnResolver;
import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils;
import org.h2.util.ValueHashMap;
import org.h2.value.CompareMode;
import org.h2.value.DataType;
......@@ -729,39 +728,40 @@ public class Aggregate extends AbstractAggregate {
return displaySize;
}
private String getSQLGroupConcat() {
StringBuilder buff = new StringBuilder("GROUP_CONCAT(");
private StringBuilder getSQLGroupConcat(StringBuilder builder) {
builder.append("GROUP_CONCAT(");
if (distinct) {
buff.append("DISTINCT ");
builder.append("DISTINCT ");
}
buff.append(on.getSQL());
Window.appendOrderBy(buff, orderByList);
on.getSQL(builder);
Window.appendOrderBy(builder, orderByList);
if (groupConcatSeparator != null) {
buff.append(" SEPARATOR ").append(groupConcatSeparator.getSQL());
builder.append(" SEPARATOR ");
groupConcatSeparator.getSQL(builder);
}
buff.append(')');
return appendTailConditions(buff).toString();
builder.append(')');
return appendTailConditions(builder);
}
private String getSQLArrayAggregate() {
StringBuilder buff = new StringBuilder("ARRAY_AGG(");
private StringBuilder getSQLArrayAggregate(StringBuilder builder) {
builder.append("ARRAY_AGG(");
if (distinct) {
buff.append("DISTINCT ");
builder.append("DISTINCT ");
}
buff.append(on.getSQL());
Window.appendOrderBy(buff, orderByList);
buff.append(')');
return appendTailConditions(buff).toString();
on.getSQL(builder);
Window.appendOrderBy(builder, orderByList);
builder.append(')');
return appendTailConditions(builder);
}
@Override
public String getSQL() {
public StringBuilder getSQL(StringBuilder builder) {
String text;
switch (type) {
case GROUP_CONCAT:
return getSQLGroupConcat();
return getSQLGroupConcat(builder);
case COUNT_ALL:
return appendTailConditions(new StringBuilder().append("COUNT(*)")).toString();
return appendTailConditions(builder.append("COUNT(*)"));
case COUNT:
text = "COUNT";
break;
......@@ -811,7 +811,7 @@ public class Aggregate extends AbstractAggregate {
text = "MEDIAN";
break;
case ARRAY_AGG:
return getSQLArrayAggregate();
return getSQLArrayAggregate(builder);
case MODE:
text = "MODE";
break;
......@@ -821,13 +821,15 @@ public class Aggregate extends AbstractAggregate {
default:
throw DbException.throwInternalError("type=" + type);
}
StringBuilder builder = new StringBuilder().append(text);
builder.append(text);
if (distinct) {
builder.append("(DISTINCT ").append(on.getSQL()).append(')');
builder.append("(DISTINCT ");
on.getSQL(builder).append(')');
} else {
builder.append(StringUtils.enclose(on.getSQL()));
builder.append('(');
on.getUnenclosedSQL(builder).append(')');
}
return appendTailConditions(builder).toString();
return appendTailConditions(builder);
}
private Index getMinMaxColumnIndex() {
......
......@@ -351,7 +351,8 @@ public abstract class DataAnalysisOperation extends Expression {
protected StringBuilder appendTailConditions(StringBuilder builder) {
if (over != null) {
builder.append(' ').append(over.getSQL());
builder.append(' ');
over.getSQL(builder);
}
return builder;
}
......
......@@ -17,7 +17,6 @@ import org.h2.expression.ExpressionVisitor;
import org.h2.message.DbException;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.util.StatementBuilder;
import org.h2.value.DataType;
import org.h2.value.Value;
import org.h2.value.ValueArray;
......@@ -68,15 +67,11 @@ public class JavaAggregate extends AbstractAggregate {
}
@Override
public String getSQL() {
StatementBuilder buff = new StatementBuilder();
buff.append(Parser.quoteIdentifier(userAggregate.getName())).append('(');
for (Expression e : args) {
buff.appendExceptFirst(", ");
buff.append(e.getSQL());
}
buff.append(')');
return appendTailConditions(buff.builder()).toString();
public StringBuilder getSQL(StringBuilder builder) {
Parser.quoteIdentifier(builder, userAggregate.getName()).append('(');
writeExpressions(builder, args);
builder.append(')');
return appendTailConditions(builder);
}
@Override
......
......@@ -15,7 +15,6 @@ import org.h2.message.DbException;
import org.h2.result.SortOrder;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.util.StringUtils;
import org.h2.value.Value;
import org.h2.value.ValueArray;
......@@ -49,7 +48,7 @@ public final class Window {
if (i > 0) {
builder.append(", ");
}
builder.append(o.expression.getSQL());
o.expression.getSQL(builder);
SortOrder.typeToString(builder, o.sortType);
}
}
......@@ -204,23 +203,22 @@ public final class Window {
}
/**
* Returns SQL representation.
* Appends SQL representation to the specified builder.
*
* @return SQL representation.
* @see Expression#getSQL()
* @param builder
* string builder
* @return the specified string builder
* @see Expression#getSQL(StringBuilder)
*/
public String getSQL() {
if (partitionBy == null && orderBy == null && frame == null) {
return "OVER ()";
}
StringBuilder builder = new StringBuilder().append("OVER (");
public StringBuilder getSQL(StringBuilder builder) {
builder.append("OVER (");
if (partitionBy != null) {
builder.append("PARTITION BY ");
for (int i = 0; i < partitionBy.size(); i++) {
if (i > 0) {
builder.append(", ");
}
builder.append(StringUtils.unEnclose(partitionBy.get(i).getSQL()));
partitionBy.get(i).getUnenclosedSQL(builder);
}
}
appendOrderBy(builder, orderBy);
......@@ -228,9 +226,9 @@ public final class Window {
if (builder.charAt(builder.length() - 1) != '(') {
builder.append(' ');
}
builder.append(frame.getSQL());
frame.getSQL(builder);
}
return builder.append(')').toString();
return builder.append(')');
}
/**
......@@ -257,7 +255,7 @@ public final class Window {
@Override
public String toString() {
return getSQL();
return getSQL(new StringBuilder()).toString();
}
}
......@@ -584,23 +584,27 @@ public final class WindowFrame {
}
/**
* Returns SQL representation.
* Append SQL representation to the specified builder.
*
* @return SQL representation.
* @see org.h2.expression.Expression#getSQL()
* @param builder
* string builder
* @return the specified string builder
* @see org.h2.expression.Expression#getSQL(StringBuilder)
*/
public String getSQL() {
StringBuilder builder = new StringBuilder();
public StringBuilder getSQL(StringBuilder builder) {
builder.append(units.getSQL());
if (following == null) {
builder.append(' ').append(starting.getSQL(false));
builder.append(' ');
starting.getSQL(builder, false);
} else {
builder.append(" BETWEEN ").append(starting.getSQL(false)).append(" AND ").append(following.getSQL(true));
builder.append(" BETWEEN ");
starting.getSQL(builder, false).append(" AND ");
following.getSQL(builder, true);
}
if (exclusion != WindowFrameExclusion.EXCLUDE_NO_OTHERS) {
builder.append(' ').append(exclusion.getSQL());
}
return builder.toString();
return builder;
}
}
......@@ -52,19 +52,21 @@ public class WindowFrameBound {
}
/**
* Returns SQL representation.
* Appends SQL representation to the specified builder.
*
* @param builder
* string builder
* @param following
* if false return SQL for starting clause, if true return SQL
* for following clause
* @return SQL representation.
* @see Expression#getSQL()
* @return the specified string builder
* @see Expression#getSQL(StringBuilder)
*/
public String getSQL(boolean following) {
public StringBuilder getSQL(StringBuilder builder, boolean following) {
if (type == WindowFrameBoundType.PRECEDING || type == WindowFrameBoundType.FOLLOWING) {
return value.getSQL() + ' ' + type.getSQL();
value.getSQL(builder).append(' ');
}
return type.getSQL();
return builder.append(type.getSQL());
}
}
......@@ -515,16 +515,11 @@ public class WindowFunction extends DataAnalysisOperation {
}
@Override
public String getSQL() {
public StringBuilder getSQL(StringBuilder builder) {
String name = type.getSQL();
StringBuilder builder = new StringBuilder().append(name).append('(');
builder.append(name).append('(');
if (args != null) {
for (int i = 0, numArgs = args.length; i < numArgs; i++) {
if (i > 0) {
builder.append(", ");
}
builder.append(args[i].getSQL());
}
writeExpressions(builder, args);
}
builder.append(')');
if (fromLast && type == WindowFunctionType.NTH_VALUE) {
......@@ -542,7 +537,7 @@ public class WindowFunction extends DataAnalysisOperation {
default:
}
}
return appendTailConditions(builder).toString();
return appendTailConditions(builder);
}
@Override
......
......@@ -514,7 +514,10 @@ public class FullText {
if (data instanceof UUID) {
return "'" + data.toString() + "'";
}
return "'" + StringUtils.convertBytesToHex((byte[]) data) + "'";
byte[] bytes = (byte[]) data;
StringBuilder builder = new StringBuilder(bytes.length * 2 + 2).append('\'');
StringUtils.convertBytesToHex(builder, bytes).append('\'');
return builder.toString();
case Types.CLOB:
case Types.JAVA_OBJECT:
case Types.OTHER:
......@@ -769,13 +772,13 @@ public class FullText {
if(!multiThread) {
buff.append(", ROLLBACK");
}
buff.append(" ON ").
append(StringUtils.quoteIdentifier(schema)).
append('.').
append(StringUtils.quoteIdentifier(table)).
buff.append(" ON ");
StringUtils.quoteIdentifier(buff, schema).
append('.');
StringUtils.quoteIdentifier(buff, table).
append(" FOR EACH ROW CALL \"").
append(FullText.FullTextTrigger.class.getName()).
append('\"');
append('"');
stat.execute(buff.toString());
}
}
......@@ -1142,7 +1145,7 @@ public class FullText {
StatementBuilder buff = new StatementBuilder();
for (int columnIndex : index.keys) {
buff.appendExceptFirst(" AND ");
buff.append(StringUtils.quoteIdentifier(index.columns[columnIndex]));
StringUtils.quoteIdentifier(buff.builder(), index.columns[columnIndex]);
Object o = row[columnIndex];
if (o == null) {
buff.append(" IS NULL");
......
......@@ -281,19 +281,19 @@ public class FullTextLucene extends FullText {
StringUtils.quoteIdentifier(TRIGGER_PREFIX + table);
stat.execute("DROP TRIGGER IF EXISTS " + trigger);
if (create) {
StringBuilder buff = new StringBuilder(
StringBuilder builder = new StringBuilder(
"CREATE TRIGGER IF NOT EXISTS ");
// the trigger is also called on rollback because transaction
// rollback will not undo the changes in the Lucene index
buff.append(trigger).
append(" AFTER INSERT, UPDATE, DELETE, ROLLBACK ON ").
append(StringUtils.quoteIdentifier(schema)).
append('.').
append(StringUtils.quoteIdentifier(table)).
builder.append(trigger).
append(" AFTER INSERT, UPDATE, DELETE, ROLLBACK ON ");
StringUtils.quoteIdentifier(builder, schema).
append('.');
StringUtils.quoteIdentifier(builder, table).
append(" FOR EACH ROW CALL \"").
append(FullTextLucene.FullTextTrigger.class.getName()).
append('\"');
stat.execute(buff.toString());
stat.execute(builder.toString());
}
}
......@@ -679,22 +679,25 @@ public class FullTextLucene extends FullText {
}
private String getQuery(Object[] row) throws SQLException {
StatementBuilder buff = new StatementBuilder();
StringBuilder builder = new StringBuilder();
if (schema != null) {
buff.append(StringUtils.quoteIdentifier(schema)).append('.');
StringUtils.quoteIdentifier(builder, schema).append('.');
}
buff.append(StringUtils.quoteIdentifier(table)).append(" WHERE ");
for (int columnIndex : keys) {
buff.appendExceptFirst(" AND ");
buff.append(StringUtils.quoteIdentifier(columns[columnIndex]));
StringUtils.quoteIdentifier(builder, table).append(" WHERE ");
for (int i = 0, length = keys.length; i < length; i++) {
if (i > 0) {
builder.append(" AND ");
}
int columnIndex = keys[i];
StringUtils.quoteIdentifier(builder, columns[columnIndex]);
Object o = row[columnIndex];
if (o == null) {
buff.append(" IS NULL");
builder.append(" IS NULL");
} else {
buff.append('=').append(FullText.quoteSQL(o, columnTypes[columnIndex]));
builder.append('=').append(FullText.quoteSQL(o, columnTypes[columnIndex]));
}
}
return buff.toString();
return builder.toString();
}
}
......
......@@ -410,7 +410,8 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
buff.append(quotedName);
buff.append(" ON ").append(targetTable.getSQL());
if (comment != null) {
buff.append(" COMMENT ").append(StringUtils.quoteStringSQL(comment));
buff.append(" COMMENT ");
StringUtils.quoteStringSQL(buff, comment);
}
buff.append('(').append(getColumnListSQL()).append(')');
return buff.toString();
......
......@@ -177,50 +177,47 @@ public class IndexCondition {
if (compareType == Comparison.FALSE) {
return "FALSE";
}
StatementBuilder buff = new StatementBuilder();
buff.append(column.getSQL());
StringBuilder builder = new StringBuilder();
builder.append(column.getSQL());
switch (compareType) {
case Comparison.EQUAL:
buff.append(" = ");
builder.append(" = ");
break;
case Comparison.EQUAL_NULL_SAFE:
buff.append(" IS ");
builder.append(" IS ");
break;
case Comparison.BIGGER_EQUAL:
buff.append(" >= ");
builder.append(" >= ");
break;
case Comparison.BIGGER:
buff.append(" > ");
builder.append(" > ");
break;
case Comparison.SMALLER_EQUAL:
buff.append(" <= ");
builder.append(" <= ");
break;
case Comparison.SMALLER:
buff.append(" < ");
builder.append(" < ");
break;
case Comparison.IN_LIST:
buff.append(" IN(");
for (Expression e : expressionList) {
buff.appendExceptFirst(", ");
buff.append(e.getSQL());
}
buff.append(')');
builder.append(" IN(");
Expression.writeExpressions(builder, expressionList);
builder.append(')');
break;
case Comparison.IN_QUERY:
buff.append(" IN(");
buff.append(expressionQuery.getPlanSQL());
buff.append(')');
builder.append(" IN(");
builder.append(expressionQuery.getPlanSQL());
builder.append(')');
break;
case Comparison.SPATIAL_INTERSECTS:
buff.append(" && ");
builder.append(" && ");
break;
default:
DbException.throwInternalError("type=" + compareType);
}
if (expression != null) {
buff.append(expression.getSQL());
expression.getSQL(builder);
}
return buff.toString();
return builder.toString();
}
/**
......
......@@ -1624,9 +1624,10 @@ public class JdbcDatabaseMetaData extends TraceObject implements
int spaceIndex = f.indexOf(' ');
if (spaceIndex >= 0) {
// remove 'Function' from 'INSERT Function'
f = StringUtils.trimSubstring(f, 0, spaceIndex);
StringUtils.trimSubstring(buff.builder(), f, 0, spaceIndex);
} else {
buff.append(f);
}
buff.append(f);
}
}
rs.close();
......@@ -3092,14 +3093,14 @@ public class JdbcDatabaseMetaData extends TraceObject implements
}
private static String getSchemaPattern(String pattern) {
return pattern == null ? "%" : pattern.length() == 0 ?
return pattern == null ? "%" : pattern.isEmpty() ?
Constants.SCHEMA_MAIN : pattern;
}
private static String getCatalogPattern(String catalogPattern) {
// Workaround for OpenOffice: getColumns is called with "" as the
// catalog
return catalogPattern == null || catalogPattern.length() == 0 ?
return catalogPattern == null || catalogPattern.isEmpty() ?
"%" : catalogPattern;
}
......
......@@ -44,8 +44,15 @@ public class JdbcXid extends TraceObject implements Xid {
* INTERNAL
*/
public static String toString(Xid xid) {
return PREFIX + '_' + xid.getFormatId() + '_' + StringUtils.convertBytesToHex(xid.getBranchQualifier()) + '_'
+ StringUtils.convertBytesToHex(xid.getGlobalTransactionId());
StringBuilder builder = new StringBuilder()
.append(PREFIX)
.append('_')
.append(xid.getFormatId())
.append('_');
StringUtils.convertBytesToHex(builder, xid.getBranchQualifier())
.append('_');
StringUtils.convertBytesToHex(builder, xid.getGlobalTransactionId());
return builder.toString();
}
/**
......
......@@ -301,8 +301,8 @@ public class Trace {
buff.append(' ');
}
buff.append("*/");
StringUtils.javaEncode(sql, buff);
StringUtils.javaEncode(params, buff);
StringUtils.javaEncode(sql, buff, false);
StringUtils.javaEncode(params, buff, false);
buff.append(';');
sql = buff.toString();
traceWriter.write(TraceSystem.INFO, module, sql, null);
......
......@@ -312,8 +312,9 @@ public class TraceObject {
if (x == null) {
return "null";
}
return "org.h2.util.StringUtils.convertHexToBytes(\"" +
StringUtils.convertBytesToHex(x) + "\")";
StringBuilder builder = new StringBuilder(x.length * 2 + 45)
.append("org.h2.util.StringUtils.convertHexToBytes(\"");
return StringUtils.convertBytesToHex(builder, x).append("\")").toString();
}
/**
......
......@@ -35,7 +35,7 @@
57014=Befehl wurde abgebrochen oder das Session-Timeout ist abgelaufen
90000=Funktion {0} muss Zeilen zurückgeben
90001=Methode nicht zulässig für eine Abfrage. Erlaubt sind execute oder executeQuery, nicht jedoch executeUpdate
90002=Methode nur zulässig for eine Abfrage. Erlaubt sind execute oder executeUpdate, nicht jedoch executeQuery
90002=Methode nur zulässig für eine Abfrage. Erlaubt sind execute oder executeUpdate, nicht jedoch executeQuery
90003=Hexadezimal Zahl mit einer ungeraden Anzahl Zeichen: {0}
90004=Hexadezimal Zahl enthält unerlaubtes Zeichen: {0}
90006=Die Sequenz {0} hat keine freien Nummern mehr
......
......@@ -12,8 +12,6 @@ import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn;
import org.h2.table.Column;
import org.h2.table.TableFilter;
import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils;
import org.h2.util.Utils;
import org.h2.value.Value;
import org.h2.value.ValueNull;
......@@ -118,18 +116,21 @@ public class SortOrder implements Comparator<Value[]> {
* @return the SQL snippet
*/
public String getSQL(Expression[] list, int visible) {
StatementBuilder buff = new StatementBuilder();
StringBuilder builder = new StringBuilder();
int i = 0;
for (int idx : queryColumnIndexes) {
buff.appendExceptFirst(", ");
if (i > 0) {
builder.append(", ");
}
if (idx < visible) {
buff.append(idx + 1);
builder.append(idx + 1);
} else {
buff.append('=').append(StringUtils.unEnclose(list[idx].getSQL()));
builder.append('=');
list[idx].getUnenclosedSQL(builder);
}
typeToString(buff.builder(), sortTypes[i++]);
typeToString(builder, sortTypes[i++]);
}
return buff.toString();
return builder.toString();
}
/**
......
......@@ -161,7 +161,7 @@ public class UpdatableRow {
for (int i = 0; i < columnCount; i++) {
buff.appendExceptFirst(",");
String col = result.getColumnName(i);
buff.append(StringUtils.quoteIdentifier(col));
StringUtils.quoteIdentifier(buff.builder(), col);
if (set) {
buff.append("=? ");
}
......@@ -173,7 +173,7 @@ public class UpdatableRow {
buff.resetCount();
for (String k : key) {
buff.appendExceptFirst(" AND ");
buff.append(StringUtils.quoteIdentifier(k)).append("=?");
StringUtils.quoteIdentifier(buff.builder(), k).append("=?");
}
}
......@@ -204,11 +204,11 @@ public class UpdatableRow {
// return rs.getInt(1) == 0;
// }
private void appendTableName(StatementBuilder buff) {
private void appendTableName(StringBuilder builder) {
if (schemaName != null && schemaName.length() > 0) {
buff.append(StringUtils.quoteIdentifier(schemaName)).append('.');
StringUtils.quoteIdentifier(builder, schemaName).append('.');
}
buff.append(StringUtils.quoteIdentifier(tableName));
StringUtils.quoteIdentifier(builder, tableName);
}
/**
......@@ -221,7 +221,7 @@ public class UpdatableRow {
StatementBuilder buff = new StatementBuilder("SELECT ");
appendColumnList(buff, false);
buff.append(" FROM ");
appendTableName(buff);
appendTableName(buff.builder());
appendKeyCondition(buff);
PreparedStatement prep = conn.prepareStatement(buff.toString());
setKey(prep, 1, row);
......@@ -245,7 +245,7 @@ public class UpdatableRow {
*/
public void deleteRow(Value[] current) throws SQLException {
StatementBuilder buff = new StatementBuilder("DELETE FROM ");
appendTableName(buff);
appendTableName(buff.builder());
appendKeyCondition(buff);
PreparedStatement prep = conn.prepareStatement(buff.toString());
setKey(prep, 1, current);
......@@ -265,7 +265,7 @@ public class UpdatableRow {
*/
public void updateRow(Value[] current, Value[] updateRow) throws SQLException {
StatementBuilder buff = new StatementBuilder("UPDATE ");
appendTableName(buff);
appendTableName(buff.builder());
buff.append(" SET ");
appendColumnList(buff, true);
// TODO updatable result set: we could add all current values to the
......@@ -297,7 +297,7 @@ public class UpdatableRow {
*/
public void insertRow(Value[] row) throws SQLException {
StatementBuilder buff = new StatementBuilder("INSERT INTO ");
appendTableName(buff);
appendTableName(buff.builder());
buff.append('(');
appendColumnList(buff, false);
buff.append(")VALUES(");
......
......@@ -38,7 +38,8 @@ public class Constant extends SchemaObjectBase {
@Override
public String getCreateSQL() {
return "CREATE CONSTANT " + getSQL() + " VALUE " + value.getSQL();
StringBuilder builder = new StringBuilder().append("CREATE CONSTANT ").append(getSQL()).append(" VALUE ");
return value.getSQL(builder).toString();
}
@Override
......
......@@ -345,9 +345,11 @@ public class TriggerObject extends SchemaObjectBase {
buff.append(" QUEUE ").append(queueSize);
}
if (triggerClassName != null) {
buff.append(" CALL ").append(Parser.quoteIdentifier(triggerClassName));
buff.append(" CALL ");
Parser.quoteIdentifier(buff, triggerClassName);
} else {
buff.append(" AS ").append(StringUtils.quoteStringSQL(triggerSource));
buff.append(" AS ");
StringUtils.quoteStringSQL(buff, triggerSource);
}
return buff.toString();
}
......
......@@ -180,7 +180,7 @@ public class PgServerThread implements Runnable {
" (" + (version >> 16) + "." + (version & 0xff) + ")");
while (true) {
String param = readString();
if (param.length() == 0) {
if (param.isEmpty()) {
break;
}
String value = readString();
......
......@@ -240,14 +240,15 @@ public class PageParser {
if (s == null) {
return null;
}
int length = s.length();
if (convertBreakAndSpace) {
if (s.length() == 0) {
if (length == 0) {
return "&nbsp;";
}
}
StringBuilder buff = new StringBuilder(s.length());
StringBuilder buff = new StringBuilder(length);
boolean convertSpace = true;
for (int i = 0; i < s.length(); i++) {
for (int i = 0; i < length; i++) {
char c = s.charAt(i);
if (c == ' ' || c == '\t') {
// convert tabs into spaces
......@@ -312,11 +313,12 @@ public class PageParser {
if (s == null) {
return null;
}
if (s.length() == 0) {
int length = s.length();
if (length == 0) {
return "";
}
StringBuilder buff = new StringBuilder(s.length());
for (int i = 0; i < s.length(); i++) {
StringBuilder buff = new StringBuilder(length);
for (int i = 0; i < length; i++) {
char c = s.charAt(i);
switch (c) {
case '"':
......
......@@ -167,7 +167,7 @@ class WebSession {
return;
}
sql = sql.trim();
if (sql.length() == 0) {
if (sql.isEmpty()) {
return;
}
if (commandHistory.size() > MAX_HISTORY) {
......
......@@ -51,7 +51,7 @@ public class FilePathZip extends FilePath {
public boolean exists() {
try {
String entryName = getEntryName();
if (entryName.length() == 0) {
if (entryName.isEmpty()) {
return true;
}
try (ZipFile file = openZipFile()) {
......@@ -88,7 +88,7 @@ public class FilePathZip extends FilePath {
public boolean isDirectory() {
try {
String entryName = getEntryName();
if (entryName.length() == 0) {
if (entryName.isEmpty()) {
return true;
}
try (ZipFile file = openZipFile()) {
......
......@@ -174,7 +174,7 @@ public class Column {
getCreateSQL();
throw DbException.get(
ErrorCode.DATA_CONVERSION_ERROR_1, e,
v.getSQL() + " (" + target + ")");
v.getTraceSQL() + " (" + target + ")");
}
throw e;
}
......@@ -496,7 +496,7 @@ public class Column {
private String getCreateSQL(boolean includeName) {
StringBuilder buff = new StringBuilder();
if (includeName && name != null) {
buff.append(Parser.quoteIdentifier(name)).append(' ');
Parser.quoteIdentifier(buff, name).append(' ');
}
if (originalSQL != null) {
buff.append(originalSQL);
......@@ -546,20 +546,17 @@ public class Column {
}
if (defaultExpression != null) {
String sql = defaultExpression.getSQL();
if (sql != null) {
if (isComputed) {
buff.append(" AS ").append(sql);
} else if (defaultExpression != null) {
buff.append(" DEFAULT ").append(sql);
}
if (isComputed) {
buff.append(" AS ");
defaultExpression.getSQL(buff);
} else if (defaultExpression != null) {
buff.append(" DEFAULT ");
defaultExpression.getSQL(buff);
}
}
if (onUpdateExpression != null) {
String sql = onUpdateExpression.getSQL();
if (sql != null) {
buff.append(" ON UPDATE ").append(sql);
}
buff.append(" ON UPDATE ");
onUpdateExpression.getSQL(buff);
}
if (!nullable) {
buff.append(" NOT NULL");
......@@ -576,7 +573,8 @@ public class Column {
buff.append(" SELECTIVITY ").append(selectivity);
}
if (comment != null) {
buff.append(" COMMENT ").append(StringUtils.quoteStringSQL(comment));
buff.append(" COMMENT ");
StringUtils.quoteStringSQL(buff, comment);
}
if (checkConstraint != null) {
buff.append(" CHECK ").append(checkConstraintSQL);
......
......@@ -49,8 +49,8 @@ public class LinkSchema {
try {
c2 = JdbcUtils.getConnection(driver, url, user, password);
stat = conn.createStatement();
stat.execute("CREATE SCHEMA IF NOT EXISTS " +
StringUtils.quoteIdentifier(targetSchema));
stat.execute(StringUtils.quoteIdentifier(new StringBuilder("CREATE SCHEMA IF NOT EXISTS "), targetSchema)
.toString());
//Workaround for PostgreSQL to avoid index names
if (url.startsWith("jdbc:postgresql:")) {
rs = c2.getMetaData().getTables(null, sourceSchema, null,
......@@ -61,29 +61,23 @@ public class LinkSchema {
while (rs.next()) {
String table = rs.getString("TABLE_NAME");
StringBuilder buff = new StringBuilder();
buff.append("DROP TABLE IF EXISTS ").
append(StringUtils.quoteIdentifier(targetSchema)).
append('.').
append(StringUtils.quoteIdentifier(table));
buff.append("DROP TABLE IF EXISTS ");
StringUtils.quoteIdentifier(buff, targetSchema).
append('.');
StringUtils.quoteIdentifier(buff, table);
stat.execute(buff.toString());
buff = new StringBuilder();
buff.append("CREATE LINKED TABLE ").
append(StringUtils.quoteIdentifier(targetSchema)).
append('.').
append(StringUtils.quoteIdentifier(table)).
append('(').
append(StringUtils.quoteStringSQL(driver)).
append(", ").
append(StringUtils.quoteStringSQL(url)).
append(", ").
append(StringUtils.quoteStringSQL(user)).
append(", ").
append(StringUtils.quoteStringSQL(password)).
append(", ").
append(StringUtils.quoteStringSQL(sourceSchema)).
append(", ").
append(StringUtils.quoteStringSQL(table)).
append(')');
buff.setLength(0);
buff.append("CREATE LINKED TABLE ");
StringUtils.quoteIdentifier(buff, targetSchema).
append('.');
StringUtils.quoteIdentifier(buff, table).
append('(');
StringUtils.quoteStringSQL(buff, driver).append(", ");
StringUtils.quoteStringSQL(buff, url).append(", ");
StringUtils.quoteStringSQL(buff, user).append(", ");
StringUtils.quoteStringSQL(buff, password).append(", ");
StringUtils.quoteStringSQL(buff, sourceSchema).append(", ");
StringUtils.quoteStringSQL(buff, table).append(')');
stat.execute(buff.toString());
result.addRow(table);
}
......
......@@ -1896,11 +1896,12 @@ public class MetaTable extends Table {
case SESSION_STATE: {
for (String name : session.getVariableNames()) {
Value v = session.getVariable(name);
StringBuilder builder = new StringBuilder().append("SET @").append(name).append(' ');
v.getSQL(builder);
add(rows,
// KEY
"@" + name,
// SQL
"SET @" + name + " " + v.getSQL()
builder.toString()
);
}
for (Table table : session.getLocalTempTables()) {
......@@ -1917,7 +1918,7 @@ public class MetaTable extends Table {
"SET SCHEMA_SEARCH_PATH ");
for (String p : path) {
buff.appendExceptFirst(", ");
buff.append(StringUtils.quoteIdentifier(p));
StringUtils.quoteIdentifier(buff.builder(), p);
}
add(rows,
// KEY
......@@ -1932,7 +1933,7 @@ public class MetaTable extends Table {
// KEY
"SCHEMA",
// SQL
"SET SCHEMA " + StringUtils.quoteIdentifier(schema)
StringUtils.quoteIdentifier(new StringBuilder("SET SCHEMA "), schema).toString()
);
}
break;
......
......@@ -72,11 +72,15 @@ public class RangeTable extends Table {
@Override
public String getSQL() {
String sql = NAME + "(" + min.getSQL() + ", " + max.getSQL();
StringBuilder builder = new StringBuilder();
builder.append(NAME).append('(');
min.getSQL(builder).append(", ");
max.getSQL(builder);
if (step != null) {
sql += ", " + step.getSQL();
builder.append(", ");
step.getSQL(builder);
}
return sql + ")";
return builder.append(')').toString();
}
@Override
......
......@@ -108,7 +108,8 @@ public abstract class TableBase extends Table {
}
buff.append(getSQL());
if (comment != null) {
buff.append(" COMMENT ").append(StringUtils.quoteStringSQL(comment));
buff.append(" COMMENT ");
StringUtils.quoteStringSQL(buff.builder(), comment);
}
buff.append("(\n ");
for (Column column : columns) {
......@@ -124,7 +125,7 @@ public abstract class TableBase extends Table {
}
if (d == null || !tableEngine.endsWith(d)) {
buff.append("\nENGINE ");
buff.append(StringUtils.quoteIdentifier(tableEngine));
StringUtils.quoteIdentifier(buff.builder(), tableEngine);
}
}
if (!tableEngineParams.isEmpty()) {
......@@ -132,7 +133,7 @@ public abstract class TableBase extends Table {
buff.resetCount();
for (String parameter : tableEngineParams) {
buff.appendExceptFirst(", ");
buff.append(StringUtils.quoteIdentifier(parameter));
StringUtils.quoteIdentifier(buff.builder(), parameter);
}
}
if (!isPersistIndexes() && !isPersistData()) {
......
......@@ -747,75 +747,77 @@ public class TableFilter implements ColumnResolver {
}
/**
* Get the query execution plan text to use for this table filter.
* Get the query execution plan text to use for this table filter and append
* it to the specified builder.
*
* @param builder string builder to append to
* @param isJoin if this is a joined table
* @return the SQL statement snippet
* @return the specified builder
*/
public String getPlanSQL(boolean isJoin) {
StringBuilder buff = new StringBuilder();
public StringBuilder getPlanSQL(StringBuilder builder, boolean isJoin) {
if (isJoin) {
if (joinOuter) {
buff.append("LEFT OUTER JOIN ");
builder.append("LEFT OUTER JOIN ");
} else {
buff.append("INNER JOIN ");
builder.append("INNER JOIN ");
}
}
if (nestedJoin != null) {
StringBuilder buffNested = new StringBuilder();
TableFilter n = nestedJoin;
do {
buffNested.append(n.getPlanSQL(n != nestedJoin));
buffNested.append('\n');
n.getPlanSQL(buffNested, n != nestedJoin).append('\n');
n = n.getJoin();
} while (n != null);
String nested = buffNested.toString();
boolean enclose = !nested.startsWith("(");
if (enclose) {
buff.append("(\n");
builder.append("(\n");
}
buff.append(StringUtils.indent(nested, 4, false));
StringUtils.indent(builder, nested, 4, false);
if (enclose) {
buff.append(')');
builder.append(')');
}
if (isJoin) {
buff.append(" ON ");
builder.append(" ON ");
if (joinCondition == null) {
// need to have a ON expression,
// otherwise the nesting is unclear
buff.append("1=1");
builder.append("1=1");
} else {
buff.append(StringUtils.unEnclose(joinCondition.getSQL()));
joinCondition.getUnenclosedSQL(builder);
}
}
return buff.toString();
return builder;
}
if (table.isView() && ((TableView) table).isRecursive()) {
buff.append(table.getSchema().getSQL()).append('.').append(Parser.quoteIdentifier(table.getName()));
builder.append(table.getSchema().getSQL()).append('.');
Parser.quoteIdentifier(builder, table.getName());
} else {
buff.append(table.getSQL());
builder.append(table.getSQL());
}
if (table.isView() && ((TableView) table).isInvalid()) {
throw DbException.get(ErrorCode.VIEW_IS_INVALID_2, table.getName(), "not compiled");
}
if (alias != null) {
buff.append(' ').append(Parser.quoteIdentifier(alias));
builder.append(' ');
Parser.quoteIdentifier(builder, alias);
}
if (indexHints != null) {
buff.append(" USE INDEX (");
builder.append(" USE INDEX (");
boolean first = true;
for (String index : indexHints.getAllowedIndexes()) {
if (!first) {
buff.append(", ");
builder.append(", ");
} else {
first = false;
}
buff.append(Parser.quoteIdentifier(index));
Parser.quoteIdentifier(builder, index);
}
buff.append(")");
builder.append(")");
}
if (index != null) {
buff.append('\n');
builder.append('\n');
StatementBuilder planBuff = new StatementBuilder();
if (joinBatch != null) {
IndexLookupBatch lookupBatch = joinBatch.getLookupBatch(joinFilterId);
......@@ -842,28 +844,28 @@ public class TableFilter implements ColumnResolver {
if (plan.indexOf('\n') >= 0) {
plan += "\n";
}
buff.append(StringUtils.indent("/* " + plan + " */", 4, false));
StringUtils.indent(builder, "/* " + plan + " */", 4, false);
}
if (isJoin) {
buff.append("\n ON ");
builder.append("\n ON ");
if (joinCondition == null) {
// need to have a ON expression, otherwise the nesting is
// unclear
buff.append("1=1");
builder.append("1=1");
} else {
buff.append(StringUtils.unEnclose(joinCondition.getSQL()));
joinCondition.getUnenclosedSQL(builder);
}
}
if (filterCondition != null) {
buff.append('\n');
builder.append('\n');
String condition = StringUtils.unEnclose(filterCondition.getSQL());
condition = "/* WHERE " + StringUtils.quoteRemarkSQL(condition) + "\n*/";
buff.append(StringUtils.indent(condition, 4, false));
StringUtils.indent(builder, condition, 4, false);
}
if (scanCount > 0) {
buff.append("\n /* scanCount: ").append(scanCount).append(" */");
builder.append("\n /* scanCount: ").append(scanCount).append(" */");
}
return buff.toString();
return builder;
}
/**
......
......@@ -372,19 +372,15 @@ public class TableLink extends Table {
}
buff.append("LINKED TABLE ").append(getSQL());
if (comment != null) {
buff.append(" COMMENT ").append(StringUtils.quoteStringSQL(comment));
buff.append(" COMMENT ");
StringUtils.quoteStringSQL(buff, comment);
}
buff.append('(').
append(StringUtils.quoteStringSQL(driver)).
append(", ").
append(StringUtils.quoteStringSQL(url)).
append(", ").
append(StringUtils.quoteStringSQL(user)).
append(", ").
append(StringUtils.quoteStringSQL(password)).
append(", ").
append(StringUtils.quoteStringSQL(originalTable)).
append(')');
buff.append('(');
StringUtils.quoteStringSQL(buff, driver).append(", ");
StringUtils.quoteStringSQL(buff, url).append(", ");
StringUtils.quoteStringSQL(buff, user).append(", ");
StringUtils.quoteStringSQL(buff, password).append(", ");
StringUtils.quoteStringSQL(buff, originalTable).append(')');
if (emitUpdates) {
buff.append(" EMIT UPDATES");
}
......@@ -510,7 +506,8 @@ public class TableLink extends Table {
int i = 1;
for (Value v : params) {
buff.appendExceptFirst(", ");
buff.append(i++).append(": ").append(v.getSQL());
buff.append(i++).append(": ");
v.getSQL(buff.builder());
}
buff.append('}');
}
......
......@@ -348,7 +348,8 @@ public class TableView extends Table {
}
buff.append(quotedName);
if (comment != null) {
buff.append(" COMMENT ").append(StringUtils.quoteStringSQL(comment));
buff.append(" COMMENT ");
StringUtils.quoteStringSQL(buff.builder(), comment);
}
if (columns != null && columns.length > 0) {
buff.append('(');
......@@ -467,7 +468,8 @@ public class TableView extends Table {
@Override
public String getSQL() {
if (isTemporary() && querySQL != null) {
return "(\n" + StringUtils.indent(querySQL) + ")";
StringBuilder builder = new StringBuilder(querySQL.length() + 16).append("(\n");
return StringUtils.indent(builder, querySQL, 4, true).append(')').toString();
}
return super.getSQL();
}
......
......@@ -108,7 +108,7 @@ public class Backup extends Tool {
private void process(String zipFileName, String directory, String db,
boolean quiet) throws SQLException {
List<String> list;
boolean allFiles = db != null && db.length() == 0;
boolean allFiles = db != null && db.isEmpty();
if (allFiles) {
list = FileUtils.newDirectoryStream(directory);
} else {
......
......@@ -228,7 +228,7 @@ public class Csv implements SimpleRowSource {
for (int i = 0; i < columnNames.length; i++) {
StringBuilder buff = new StringBuilder();
String n = columnNames[i];
if (n == null || n.length() == 0) {
if (n == null || n.isEmpty()) {
buff.append('C').append(i + 1);
} else {
buff.append(n);
......@@ -350,7 +350,7 @@ public class Csv implements SimpleRowSource {
list.add(v);
}
} else {
if (v.length() == 0) {
if (v.isEmpty()) {
v = "COLUMN" + list.size();
} else if (!caseSensitiveColumnNames && isSimpleColumnName(v)) {
v = StringUtils.toUpperEnglish(v);
......@@ -827,13 +827,13 @@ public class Csv implements SimpleRowSource {
String charset = null;
String[] keyValuePairs = StringUtils.arraySplit(options, ' ', false);
for (String pair : keyValuePairs) {
if (pair.length() == 0) {
if (pair.isEmpty()) {
continue;
}
int index = pair.indexOf('=');
String key = StringUtils.trim(pair.substring(0, index), true, true, " ");
String value = pair.substring(index + 1);
char ch = value.length() == 0 ? 0 : value.charAt(0);
char ch = value.isEmpty() ? 0 : value.charAt(0);
if (isParam(key, "escape", "esc", "escapeCharacter")) {
setEscapeCharacter(ch);
} else if (isParam(key, "fieldDelimiter", "fieldDelim")) {
......
......@@ -156,12 +156,13 @@ public class MultiDimension implements Comparator<long[]> {
public String generatePreparedQuery(String table, String scalarColumn,
String[] columns) {
StringBuilder buff = new StringBuilder("SELECT D.* FROM ");
buff.append(StringUtils.quoteIdentifier(table)).
append(" D, TABLE(_FROM_ BIGINT=?, _TO_ BIGINT=?) WHERE ").
append(StringUtils.quoteIdentifier(scalarColumn)).
StringUtils.quoteIdentifier(buff, table).
append(" D, TABLE(_FROM_ BIGINT=?, _TO_ BIGINT=?) WHERE ");
StringUtils.quoteIdentifier(buff, scalarColumn).
append(" BETWEEN _FROM_ AND _TO_");
for (String col : columns) {
buff.append(" AND ").append(StringUtils.quoteIdentifier(col)).
buff.append(" AND ");
StringUtils.quoteIdentifier(buff, col).
append("+1 BETWEEN ?+1 AND ?+1");
}
return buff.toString();
......
......@@ -417,7 +417,7 @@ public class Recover extends Tool implements DataHandler {
}
}
private String getSQL(String column, Value v) {
private void getSQL(StringBuilder builder, String column, Value v) {
if (v instanceof ValueLob) {
ValueLob lob = (ValueLob) v;
byte[] small = lob.getSmall();
......@@ -428,7 +428,8 @@ public class Recover extends Tool implements DataHandler {
dumpLob(file, true);
file += ".comp";
}
return "READ_" + type + "('" + file + ".txt')";
builder.append("READ_").append(type).append("('").append(file).append(".txt')");
return;
}
} else if (v instanceof ValueLobDb) {
ValueLobDb lob = (ValueLobDb) v;
......@@ -437,25 +438,25 @@ public class Recover extends Tool implements DataHandler {
int type = lob.getType();
long id = lob.getLobId();
long precision = lob.getPrecision();
String m;
String columnType;
if (type == Value.BLOB) {
columnType = "BLOB";
m = "READ_BLOB";
builder.append("READ_BLOB");
} else {
columnType = "CLOB";
m = "READ_CLOB";
builder.append("READ_CLOB");
}
if (lobMaps) {
m += "_MAP";
builder.append("_MAP");
} else {
m += "_DB";
builder.append("_DB");
}
columnTypeMap.put(column, columnType);
return m + "(" + id + ", " + precision + ")";
builder.append('(').append(id).append(", ").append(precision).append(')');
return;
}
}
return v.getSQL();
v.getSQL(builder);
}
private void setDatabaseName(String name) {
......@@ -666,9 +667,11 @@ public class Recover extends Tool implements DataHandler {
if (!init) {
setStorage(Integer.parseInt(tableId));
// init the column types
StringBuilder builder = new StringBuilder();
for (valueId = 0; valueId < recordLength; valueId++) {
String columnName = storageName + "." + valueId;
getSQL(columnName, values[valueId]);
builder.setLength(0);
getSQL(builder, columnName, values[valueId]);
}
createTemporaryTable(writer);
init = true;
......@@ -681,7 +684,7 @@ public class Recover extends Tool implements DataHandler {
buff.append(", ");
}
String columnName = storageName + "." + valueId;
buff.append(getSQL(columnName, values[valueId]));
getSQL(buff, columnName, values[valueId]);
}
buff.append(");");
writer.println(buff.toString());
......@@ -729,10 +732,11 @@ public class Recover extends Tool implements DataHandler {
try {
for (int seq = 0;; seq++) {
int l = IOUtils.readFully(in, block, block.length);
String x = StringUtils.convertBytesToHex(block, l);
if (l > 0) {
writer.println("INSERT INTO INFORMATION_SCHEMA.LOB_BLOCKS " +
"VALUES(" + lobId + ", " + seq + ", '" + x + "');");
writer.print("INSERT INTO INFORMATION_SCHEMA.LOB_BLOCKS " +
"VALUES(" + lobId + ", " + seq + ", '");
writer.print(StringUtils.convertBytesToHex(block, l));
writer.println("');");
}
if (l != len) {
break;
......@@ -991,7 +995,7 @@ public class Recover extends Tool implements DataHandler {
append(" VALUES(");
for (int i = 0; i < row.getColumnCount(); i++) {
buff.appendExceptFirst(", ");
buff.append(row.getValue(i).getSQL());
row.getValue(i).getSQL(buff.builder());
}
buff.append(");");
writer.println(buff.toString());
......@@ -1443,12 +1447,12 @@ public class Recover extends Tool implements DataHandler {
byte[] salt = MathUtils.secureRandomBytes(Constants.SALT_LEN);
byte[] passwordHash = SHA256.getHashWithSalt(
userPasswordHash, salt);
StringBuilder buff = new StringBuilder();
buff.append("SALT '").
append(StringUtils.convertBytesToHex(salt)).
append("' HASH '").
append(StringUtils.convertBytesToHex(passwordHash)).
append('\'');
StringBuilder buff = new StringBuilder()
.append("SALT '");
StringUtils.convertBytesToHex(buff, salt)
.append("' HASH '");
StringUtils.convertBytesToHex(buff, passwordHash)
.append('\'');
byte[] replacement = buff.toString().getBytes();
System.arraycopy(replacement, 0, s.getBytes(),
saltIndex, replacement.length);
......@@ -1497,7 +1501,7 @@ public class Recover extends Tool implements DataHandler {
sb.append(", ");
}
String columnName = storageName + "." + valueId;
sb.append(getSQL(columnName, v));
getSQL(sb, columnName, v);
} catch (Exception e) {
writeDataError(writer, "exception " + e, s.getBytes());
} catch (OutOfMemoryError e) {
......
......@@ -205,7 +205,7 @@ public class RunScript extends Tool {
break;
}
String trim = sql.trim();
if (trim.length() == 0) {
if (trim.isEmpty()) {
continue;
}
if (trim.startsWith("@") && StringUtils.toUpperEnglish(trim).
......
......@@ -220,7 +220,7 @@ public class Shell extends Tool implements Runnable {
break;
}
String trimmed = line.trim();
if (trimmed.length() == 0) {
if (trimmed.isEmpty()) {
continue;
}
boolean end = trimmed.endsWith(";");
......@@ -366,7 +366,7 @@ public class Shell extends Tool implements Runnable {
println("[Enter] Hide");
print("Password ");
String password = readLine();
if (password.length() == 0) {
if (password.isEmpty()) {
password = readPassword();
}
conn = JdbcUtils.getConnection(driver, url, user, password);
......@@ -433,7 +433,7 @@ public class Shell extends Tool implements Runnable {
private String readLine(String defaultValue) throws IOException {
String s = readLine();
return s.length() == 0 ? defaultValue : s;
return s.isEmpty() ? defaultValue : s;
}
private String readLine() throws IOException {
......
......@@ -6,7 +6,7 @@ package org.h2.util;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.h2.engine.Session;
import org.h2.expression.Expression;
......@@ -57,51 +57,23 @@ public class ColumnNamer {
*/
public String getColumnName(Expression columnExp, int indexOfColumn, String columnNameOverride) {
// try a name from the column name override
String columnName = null;
if (columnNameOverride != null) {
columnName = columnNameOverride;
if (!isAllowableColumnName(columnName)) {
columnName = fixColumnName(columnName);
}
if (!isAllowableColumnName(columnName)) {
columnName = null;
}
}
// try a name from the column alias
if (columnName == null && columnExp.getAlias() != null && !DEFAULT_COLUMN_NAME.equals(columnExp.getAlias())) {
columnName = columnExp.getAlias();
if (!isAllowableColumnName(columnName)) {
columnName = fixColumnName(columnName);
}
if (!isAllowableColumnName(columnName)) {
columnName = null;
}
}
// try a name derived from the column expression SQL
if (columnName == null && columnExp.getColumnName() != null
&& !DEFAULT_COLUMN_NAME.equals(columnExp.getColumnName())) {
columnName = columnExp.getColumnName();
if (!isAllowableColumnName(columnName)) {
columnName = fixColumnName(columnName);
}
if (!isAllowableColumnName(columnName)) {
columnName = null;
}
}
// try a name derived from the column expression plan SQL
if (columnName == null && columnExp.getSQL() != null && !DEFAULT_COLUMN_NAME.equals(columnExp.getSQL())) {
columnName = columnExp.getSQL();
if (!isAllowableColumnName(columnName)) {
columnName = fixColumnName(columnName);
}
if (!isAllowableColumnName(columnName)) {
columnName = null;
}
}
// go with a innocuous default name pattern
String columnName = getColumnName(columnNameOverride, null);
if (columnName == null) {
columnName = configuration.getDefaultColumnNamePattern()
.replace("$$", Integer.toString(indexOfColumn + 1));
// try a name from the column alias
columnName = getColumnName(columnExp.getAlias(), DEFAULT_COLUMN_NAME);
if (columnName == null) {
// try a name derived from the column expression SQL
columnName = getColumnName(columnExp.getColumnName(), DEFAULT_COLUMN_NAME);
if (columnName == null) {
// try a name derived from the column expression plan SQL
columnName = getColumnName(columnExp.getSQL(), DEFAULT_COLUMN_NAME);
// go with a innocuous default name pattern
if (columnName == null) {
columnName = configuration.getDefaultColumnNamePattern()
.replace("$$", Integer.toString(indexOfColumn + 1));
}
}
}
}
if (existingColumnNames.contains(columnName) && configuration.isGenerateUniqueColumnNames()) {
columnName = generateUniqueName(columnName);
......@@ -110,6 +82,21 @@ public class ColumnNamer {
return columnName;
}
private String getColumnName(String proposedName, String disallowedName) {
String columnName = null;
if (proposedName != null && !proposedName.equals(disallowedName)) {
if (isAllowableColumnName(proposedName)) {
columnName = proposedName;
} else {
proposedName = fixColumnName(proposedName);
if (isAllowableColumnName(proposedName)) {
columnName = proposedName;
}
}
}
return columnName;
}
private String generateUniqueName(String columnName) {
String newColumnName = columnName;
int loopCount = 2;
......@@ -124,26 +111,31 @@ public class ColumnNamer {
}
private boolean isAllowableColumnName(String proposedName) {
// check null
if (proposedName == null) {
return false;
}
// check size limits
if (proposedName.length() > configuration.getMaxIdentiferLength() || proposedName.length() == 0) {
int length = proposedName.length();
if (length > configuration.getMaxIdentiferLength() || length == 0) {
return false;
}
Matcher match = configuration.getCompiledRegularExpressionMatchAllowed().matcher(proposedName);
return match.matches();
Pattern allowed = configuration.getCompiledRegularExpressionMatchAllowed();
return allowed == null || allowed.matcher(proposedName).matches();
}
private String fixColumnName(String proposedName) {
Matcher match = configuration.getCompiledRegularExpressionMatchDisallowed().matcher(proposedName);
proposedName = match.replaceAll("");
Pattern disallowed = configuration.getCompiledRegularExpressionMatchDisallowed();
if (disallowed == null) {
proposedName = StringUtils.replaceAll(proposedName, "\u0000", "");
} else {
proposedName = disallowed.matcher(proposedName).replaceAll("");
}
// check size limits - then truncate
if (proposedName.length() > configuration.getMaxIdentiferLength()) {
proposedName = proposedName.substring(0, configuration.getMaxIdentiferLength());
int length = proposedName.length(), maxLength = configuration.getMaxIdentiferLength();
if (length > maxLength) {
proposedName = proposedName.substring(0, maxLength);
}
return proposedName;
......
......@@ -40,8 +40,7 @@ public class ColumnNamerConfiguration {
this.defaultColumnNamePattern = defaultColumnNamePattern;
this.generateUniqueColumnNames = generateUniqueColumnNames;
compiledRegularExpressionMatchAllowed = Pattern.compile(regularExpressionMatchAllowed);
compiledRegularExpressionMatchDisallowed = Pattern.compile(regularExpressionMatchDisallowed);
recompilePatterns();
}
public int getMaxIdentiferLength() {
......@@ -80,6 +79,11 @@ public class ColumnNamerConfiguration {
this.defaultColumnNamePattern = defaultColumnNamePattern;
}
/**
* Returns compiled pattern for allowed names.
*
* @return compiled pattern, or null for default
*/
public Pattern getCompiledRegularExpressionMatchAllowed() {
return compiledRegularExpressionMatchAllowed;
}
......@@ -88,6 +92,11 @@ public class ColumnNamerConfiguration {
this.compiledRegularExpressionMatchAllowed = compiledRegularExpressionMatchAllowed;
}
/**
* Returns compiled pattern for disallowed names.
*
* @return compiled pattern, or null for default
*/
public Pattern getCompiledRegularExpressionMatchDisallowed() {
return compiledRegularExpressionMatchDisallowed;
}
......@@ -138,8 +147,11 @@ public class ColumnNamerConfiguration {
private void recompilePatterns() {
try {
// recompile RE patterns
setCompiledRegularExpressionMatchAllowed(Pattern.compile(getRegularExpressionMatchAllowed()));
setCompiledRegularExpressionMatchDisallowed(Pattern.compile(getRegularExpressionMatchDisallowed()));
setCompiledRegularExpressionMatchAllowed(
regularExpressionMatchAllowed != null ? Pattern.compile(regularExpressionMatchAllowed) : null);
setCompiledRegularExpressionMatchDisallowed(
regularExpressionMatchDisallowed != null ? Pattern.compile(regularExpressionMatchDisallowed)
: null);
} catch (Exception e) {
configure(REGULAR);
throw e;
......@@ -147,7 +159,7 @@ public class ColumnNamerConfiguration {
}
public static ColumnNamerConfiguration getDefault() {
return new ColumnNamerConfiguration(Integer.MAX_VALUE, "(?m)(?s).+", "(?m)(?s)[\\x00]", "_UNNAMED_$$", false);
return new ColumnNamerConfiguration(Integer.MAX_VALUE, null, null, "_UNNAMED_$$", false);
}
private static String unquoteString(String s) {
......@@ -220,8 +232,8 @@ public class ColumnNamerConfiguration {
case Ignite:
default:
setMaxIdentiferLength(Integer.MAX_VALUE);
setRegularExpressionMatchAllowed("(?m)(?s).+");
setRegularExpressionMatchDisallowed("(?m)(?s)[\\x00]");
setRegularExpressionMatchAllowed(null);
setRegularExpressionMatchDisallowed(null);
setDefaultColumnNamePattern("_UNNAMED_$$");
setGenerateUniqueColumnNames(false);
break;
......
......@@ -1511,18 +1511,17 @@ public class DateTimeUtils {
/**
* Formats timestamp with time zone as string.
*
* @param buff the target string builder
* @param dateValue the year-month-day bit field
* @param timeNanos nanoseconds since midnight
* @param timeZoneOffsetMins the time zone offset in minutes
* @return formatted string
*/
public static String timestampTimeZoneToString(long dateValue, long timeNanos, short timeZoneOffsetMins) {
StringBuilder buff = new StringBuilder(ValueTimestampTimeZone.MAXIMUM_PRECISION);
public static void appendTimestampTimeZone(StringBuilder buff, long dateValue, long timeNanos,
short timeZoneOffsetMins) {
appendDate(buff, dateValue);
buff.append(' ');
appendTime(buff, timeNanos);
appendTimeZone(buff, timeZoneOffsetMins);
return buff.toString();
}
/**
......
......@@ -383,8 +383,11 @@ public class IntervalUtils {
}
/**
* Formats interval as a string.
* Formats interval as a string and appends it to a specified string
* builder.
*
* @param buff
* string builder to append to
* @param qualifier
* qualifier of the interval
* @param negative
......@@ -393,12 +396,11 @@ public class IntervalUtils {
* the value of leading field
* @param remaining
* the value of all remaining fields
* @return string representation of the specified interval
* @return the specified string builder
*/
public static String intervalToString(IntervalQualifier qualifier, boolean negative, long leading, long remaining)
{
StringBuilder buff = new StringBuilder().append("INTERVAL ");
buff.append('\'');
public static StringBuilder appendInterval(StringBuilder buff, IntervalQualifier qualifier, boolean negative,
long leading, long remaining) {
buff.append("INTERVAL '");
if (negative) {
buff.append('-');
}
......@@ -453,8 +455,7 @@ public class IntervalUtils {
appendSecondsWithNanos(buff, remaining);
break;
}
buff.append("' ").append(qualifier);
return buff.toString();
return buff.append("' ").append(qualifier);
}
private static void appendSecondsWithNanos(StringBuilder buff, long nanos) {
......
......@@ -155,7 +155,7 @@ public class NetUtils {
*/
private static InetAddress getBindAddress() throws UnknownHostException {
String host = SysProperties.BIND_ADDRESS;
if (host == null || host.length() == 0) {
if (host == null || host.isEmpty()) {
return null;
}
synchronized (NetUtils.class) {
......
......@@ -238,10 +238,11 @@ public class ParserUtil {
* @return true if it is a keyword
*/
public static boolean isKeyword(String s) {
if (s.length() == 0) {
int length = s.length();
if (length == 0) {
return false;
}
return getSaveTokenType(s, false) != IDENTIFIER;
return getSaveTokenType(s, false, 0, length, false) != IDENTIFIER;
}
/**
......@@ -252,7 +253,8 @@ public class ParserUtil {
* @throws NullPointerException if s is {@code null}
*/
public static boolean isSimpleIdentifier(String s) {
if (s.length() == 0) {
int length = s.length();
if (length == 0) {
return false;
}
char c = s.charAt(0);
......@@ -260,182 +262,196 @@ public class ParserUtil {
if ((UPPER_OR_OTHER_LETTER >>> Character.getType(c) & 1) == 0 && c != '_') {
return false;
}
for (int i = 1, length = s.length(); i < length; i++) {
for (int i = 1; i < length; i++) {
c = s.charAt(i);
if ((UPPER_OR_OTHER_LETTER_OR_DIGIT >>> Character.getType(c) & 1) == 0 && c != '_') {
return false;
}
}
return getSaveTokenType(s, true) == IDENTIFIER;
return getSaveTokenType(s, false, 0, length, true) == IDENTIFIER;
}
/**
* Get the token type.
*
* @param s the token
* @param s the string with token
* @param ignoreCase true if case should be ignored, false if only upper case
* tokens are detected as keywords
* @param start start index of token
* @param end index of token
* @param additionalKeywords whether TOP, INTERSECTS, and "current data /
* time" functions are keywords
* @return the token type
*/
public static int getSaveTokenType(String s, boolean additionalKeywords) {
public static int getSaveTokenType(String s, boolean ignoreCase, int start, int end, boolean additionalKeywords) {
/*
* JdbcDatabaseMetaData.getSQLKeywords() and tests should be updated when new
* non-SQL:2003 keywords are introduced here.
*/
switch (s.charAt(0)) {
char c = s.charAt(start);
if (ignoreCase) {
/*
* Convert a-z to A-Z. This method is safe, because only A-Z
* characters are considered below.
*/
c &= 0xffdf;
}
switch (c) {
case 'A':
if ("ALL".equals(s)) {
if (eq("ALL", s, ignoreCase, start, end)) {
return ALL;
}
return IDENTIFIER;
case 'C':
if ("CHECK".equals(s)) {
if (eq("CHECK", s, ignoreCase, start, end)) {
return CHECK;
} else if ("CONSTRAINT".equals(s)) {
} else if (eq("CONSTRAINT", s, ignoreCase, start, end)) {
return CONSTRAINT;
} else if ("CROSS".equals(s)) {
} else if (eq("CROSS", s, ignoreCase, start, end)) {
return CROSS;
}
if (additionalKeywords) {
if ("CURRENT_DATE".equals(s) || "CURRENT_TIME".equals(s) || "CURRENT_TIMESTAMP".equals(s)) {
if (eq("CURRENT_DATE", s, ignoreCase, start, end) || eq("CURRENT_TIME", s, ignoreCase, start, end)
|| eq("CURRENT_TIMESTAMP", s, ignoreCase, start, end)) {
return KEYWORD;
}
}
return IDENTIFIER;
case 'D':
if ("DISTINCT".equals(s)) {
if (eq("DISTINCT", s, ignoreCase, start, end)) {
return DISTINCT;
}
return IDENTIFIER;
case 'E':
if ("EXCEPT".equals(s)) {
if (eq("EXCEPT", s, ignoreCase, start, end)) {
return EXCEPT;
} else if ("EXISTS".equals(s)) {
} else if (eq("EXISTS", s, ignoreCase, start, end)) {
return EXISTS;
}
return IDENTIFIER;
case 'F':
if ("FETCH".equals(s)) {
if (eq("FETCH", s, ignoreCase, start, end)) {
return FETCH;
} else if ("FROM".equals(s)) {
} else if (eq("FROM", s, ignoreCase, start, end)) {
return FROM;
} else if ("FOR".equals(s)) {
} else if (eq("FOR", s, ignoreCase, start, end)) {
return FOR;
} else if ("FOREIGN".equals(s)) {
} else if (eq("FOREIGN", s, ignoreCase, start, end)) {
return FOREIGN;
} else if ("FULL".equals(s)) {
} else if (eq("FULL", s, ignoreCase, start, end)) {
return FULL;
} else if ("FALSE".equals(s)) {
} else if (eq("FALSE", s, ignoreCase, start, end)) {
return FALSE;
}
return IDENTIFIER;
case 'G':
if ("GROUP".equals(s)) {
if (eq("GROUP", s, ignoreCase, start, end)) {
return GROUP;
}
return IDENTIFIER;
case 'H':
if ("HAVING".equals(s)) {
if (eq("HAVING", s, ignoreCase, start, end)) {
return HAVING;
}
return IDENTIFIER;
case 'I':
if ("INNER".equals(s)) {
if (eq("INNER", s, ignoreCase, start, end)) {
return INNER;
} else if ("INTERSECT".equals(s)) {
} else if (eq("INTERSECT", s, ignoreCase, start, end)) {
return INTERSECT;
} else if ("IS".equals(s)) {
} else if (eq("IS", s, ignoreCase, start, end)) {
return IS;
}
if (additionalKeywords) {
if ("INTERSECTS".equals(s)) {
if (eq("INTERSECTS", s, ignoreCase, start, end)) {
return KEYWORD;
}
}
return IDENTIFIER;
case 'J':
if ("JOIN".equals(s)) {
if (eq("JOIN", s, ignoreCase, start, end)) {
return JOIN;
}
return IDENTIFIER;
case 'L':
if ("LIMIT".equals(s)) {
if (eq("LIMIT", s, ignoreCase, start, end)) {
return LIMIT;
} else if ("LIKE".equals(s)) {
} else if (eq("LIKE", s, ignoreCase, start, end)) {
return LIKE;
}
if (additionalKeywords) {
if ("LOCALTIME".equals(s) || "LOCALTIMESTAMP".equals(s)) {
if (eq("LOCALTIME", s, ignoreCase, start, end) || eq("LOCALTIMESTAMP", s, ignoreCase, start, end)) {
return KEYWORD;
}
}
return IDENTIFIER;
case 'M':
if ("MINUS".equals(s)) {
if (eq("MINUS", s, ignoreCase, start, end)) {
return MINUS;
}
return IDENTIFIER;
case 'N':
if ("NOT".equals(s)) {
if (eq("NOT", s, ignoreCase, start, end)) {
return NOT;
} else if ("NATURAL".equals(s)) {
} else if (eq("NATURAL", s, ignoreCase, start, end)) {
return NATURAL;
} else if ("NULL".equals(s)) {
} else if (eq("NULL", s, ignoreCase, start, end)) {
return NULL;
}
return IDENTIFIER;
case 'O':
if ("OFFSET".equals(s)) {
if (eq("OFFSET", s, ignoreCase, start, end)) {
return OFFSET;
} else if ("ON".equals(s)) {
} else if (eq("ON", s, ignoreCase, start, end)) {
return ON;
} else if ("ORDER".equals(s)) {
} else if (eq("ORDER", s, ignoreCase, start, end)) {
return ORDER;
}
return IDENTIFIER;
case 'P':
if ("PRIMARY".equals(s)) {
if (eq("PRIMARY", s, ignoreCase, start, end)) {
return PRIMARY;
}
return IDENTIFIER;
case 'R':
if ("ROWNUM".equals(s)) {
if (eq("ROWNUM", s, ignoreCase, start, end)) {
return ROWNUM;
}
return IDENTIFIER;
case 'S':
if ("SELECT".equals(s)) {
if (eq("SELECT", s, ignoreCase, start, end)) {
return SELECT;
}
if (additionalKeywords) {
if ("SYSDATE".equals(s) || "SYSTIME".equals(s) || "SYSTIMESTAMP".equals(s)) {
if (eq("SYSDATE", s, ignoreCase, start, end) || eq("SYSTIME", s, ignoreCase, start, end)
|| eq("SYSTIMESTAMP", s, ignoreCase, start, end)) {
return KEYWORD;
}
}
return IDENTIFIER;
case 'T':
if ("TRUE".equals(s)) {
if (eq("TRUE", s, ignoreCase, start, end)) {
return TRUE;
}
if (additionalKeywords) {
if ("TODAY".equals(s) || "TOP".equals(s)) {
if (eq("TODAY", s, ignoreCase, start, end) || eq("TOP", s, ignoreCase, start, end)) {
return KEYWORD;
}
}
return IDENTIFIER;
case 'U':
if ("UNIQUE".equals(s)) {
if (eq("UNIQUE", s, ignoreCase, start, end)) {
return UNIQUE;
} else if ("UNION".equals(s)) {
} else if (eq("UNION", s, ignoreCase, start, end)) {
return UNION;
}
return IDENTIFIER;
case 'W':
if ("WHERE".equals(s)) {
if (eq("WHERE", s, ignoreCase, start, end)) {
return WHERE;
} else if ("WINDOW".equals(s)) {
} else if (eq("WINDOW", s, ignoreCase, start, end)) {
return WINDOW;
} else if ("WITH".equals(s)) {
} else if (eq("WITH", s, ignoreCase, start, end)) {
return WITH;
}
return IDENTIFIER;
......@@ -444,4 +460,10 @@ public class ParserUtil {
}
}
private static boolean eq(String expected, String s, boolean ignoreCase, int start, int end) {
int len = expected.length();
// First letter was already checked
return end - start == len && expected.regionMatches(ignoreCase, 1, s, start + 1, len - 1);
}
}
......@@ -121,22 +121,41 @@ public class StringUtils {
if (s == null) {
return "NULL";
}
return quoteStringSQL(new StringBuilder(s.length() + 2), s).toString();
}
/**
* Convert a string to a SQL literal. Null is converted to NULL. The text is
* enclosed in single quotes. If there are any special characters, the
* method STRINGDECODE is used.
*
* @param builder
* string builder to append result to
* @param s the text to convert.
* @return the specified string builder
*/
public static StringBuilder quoteStringSQL(StringBuilder builder, String s) {
if (s == null) {
return builder.append("NULL");
}
int builderLength = builder.length();
int length = s.length();
StringBuilder buff = new StringBuilder(length + 2);
buff.append('\'');
builder.append('\'');
for (int i = 0; i < length; i++) {
char c = s.charAt(i);
if (c == '\'') {
buff.append(c);
builder.append(c);
} else if (c < ' ' || c > 127) {
// need to start from the beginning because maybe there was a \
// that was not quoted
return "STRINGDECODE(" + quoteStringSQL(javaEncode(s)) + ")";
builder.setLength(builderLength);
builder.append("STRINGDECODE('");
javaEncode(s, builder, true);
return builder.append("')");
}
buff.append(c);
builder.append(c);
}
buff.append('\'');
return buff.toString();
return builder.append('\'');
}
/**
......@@ -149,11 +168,11 @@ public class StringUtils {
*/
public static String javaEncode(String s) {
StringBuilder buff = new StringBuilder(s.length());
javaEncode(s, buff);
javaEncode(s, buff, false);
return buff.toString();
}
public static void javaEncode(String s, StringBuilder buff) {
public static void javaEncode(String s, StringBuilder buff, boolean forSQL) {
int length = s.length();
for (int i = 0; i < length; i++) {
char c = s.charAt(i);
......@@ -183,27 +202,31 @@ public class StringUtils {
// double quote
buff.append("\\\"");
break;
case '\'':
// quote:
if (forSQL) {
buff.append('\'');
}
buff.append('\'');
break;
case '\\':
// backslash
buff.append("\\\\");
break;
default:
int ch = c & 0xffff;
if (ch >= ' ' && (ch < 0x80)) {
if (c >= ' ' && (c < 0x80)) {
buff.append(c);
// not supported in properties files
// } else if (ch < 0xff) {
// } else if (c < 0xff) {
// buff.append("\\");
// // make sure it's three characters (0x200 is octal 1000)
// buff.append(Integer.toOctalString(0x200 | ch).substring(1));
// buff.append(Integer.toOctalString(0x200 | c).substring(1));
} else {
buff.append("\\u");
String hex = Integer.toHexString(ch);
// make sure it's four characters
for (int len = hex.length(); len < 4; len++) {
buff.append('0');
}
buff.append(hex);
buff.append("\\u")
.append(HEX[c >>> 12])
.append(HEX[c >>> 8 & 0xf])
.append(HEX[c >>> 4 & 0xf])
.append(HEX[c & 0xf]);
}
}
}
......@@ -321,7 +344,9 @@ public class StringUtils {
if (s == null) {
return "null";
}
return "\"" + javaEncode(s) + "\"";
StringBuilder builder = new StringBuilder(s.length() + 2).append('"');
javaEncode(s, builder, false);
return builder.append('"').toString();
}
/**
......@@ -362,19 +387,6 @@ public class StringUtils {
return buff.append('}').toString();
}
/**
* Enclose a string with '(' and ')' if this is not yet done.
*
* @param s the string
* @return the enclosed string
*/
public static String enclose(String s) {
if (s.startsWith("(")) {
return s;
}
return "(" + s + ")";
}
/**
* Remove enclosing '(' and ')' if this text is enclosed.
*
......@@ -535,49 +547,49 @@ public class StringUtils {
*/
public static String xmlNode(String name, String attributes,
String content, boolean indent) {
String start = attributes == null ? name : name + attributes;
StringBuilder builder = new StringBuilder();
builder.append('<').append(name);
if (attributes != null) {
builder.append(attributes);
}
if (content == null) {
return "<" + start + "/>\n";
builder.append("/>\n");
return builder.toString();
}
builder.append('>');
if (indent && content.indexOf('\n') >= 0) {
content = "\n" + indent(content);
builder.append('\n');
indent(builder, content, 4, true);
} else {
builder.append(content);
}
return "<" + start + ">" + content + "</" + name + ">\n";
builder.append("</").append(name).append(">\n");
return builder.toString();
}
/**
* Indents a string with 4 spaces.
*
* @param s the string
* @return the indented string
*/
public static String indent(String s) {
return indent(s, 4, true);
}
/**
* Indents a string with spaces.
* Indents a string with spaces and appends it to a specified builder.
*
* @param builder string builder to append to
* @param s the string
* @param spaces the number of spaces
* @param newline append a newline if there is none
* @return the indented string
* @return the specified string builder
*/
public static String indent(String s, int spaces, boolean newline) {
StringBuilder buff = new StringBuilder(s.length() + spaces);
for (int i = 0; i < s.length();) {
public static StringBuilder indent(StringBuilder builder, String s, int spaces, boolean newline) {
for (int i = 0, length = s.length(); i < length;) {
for (int j = 0; j < spaces; j++) {
buff.append(' ');
builder.append(' ');
}
int n = s.indexOf('\n', i);
n = n < 0 ? s.length() : n + 1;
buff.append(s, i, n);
n = n < 0 ? length : n + 1;
builder.append(s, i, n);
i = n;
}
if (newline && !s.endsWith("\n")) {
buff.append('\n');
builder.append('\n');
}
return buff.toString();
return builder;
}
/**
......@@ -600,7 +612,8 @@ public class StringUtils {
// must have a space at the beginning and at the end,
// otherwise the data must not contain '-' as the first/last character
if (data.indexOf('\n') >= 0) {
return "<!--\n" + indent(data) + "-->\n";
StringBuilder builder = new StringBuilder(data.length() + 18).append("<!--\n");
return indent(builder, data, 4, true).append("-->\n").toString();
}
return "<!-- " + data + " -->\n";
}
......@@ -733,17 +746,28 @@ public class StringUtils {
* @return the double quoted text
*/
public static String quoteIdentifier(String s) {
int length = s.length();
StringBuilder buff = new StringBuilder(length + 2);
buff.append('\"');
for (int i = 0; i < length; i++) {
return quoteIdentifier(new StringBuilder(s.length() + 2), s).toString();
}
/**
* Enclose a string with double quotes and append it to the specified
* string builder. A double quote inside the string is escaped using a
* double quote.
*
* @param builder string builder to append to
* @param s the text
* @return the specified builder
*/
public static StringBuilder quoteIdentifier(StringBuilder builder, String s) {
builder.append('"');
for (int i = 0, length = s.length(); i < length; i++) {
char c = s.charAt(i);
if (c == '"') {
buff.append(c);
builder.append(c);
}
buff.append(c);
builder.append(c);
}
return buff.append('\"').toString();
return builder.append('"');
}
/**
......@@ -753,7 +777,7 @@ public class StringUtils {
* @return true if it is null or empty
*/
public static boolean isNullOrEmpty(String s) {
return s == null || s.length() == 0;
return s == null || s.isEmpty();
}
/**
......@@ -786,7 +810,7 @@ public class StringUtils {
return string;
}
char paddingChar;
if (padding == null || padding.length() == 0) {
if (padding == null || padding.isEmpty()) {
paddingChar = ' ';
} else {
paddingChar = padding.charAt(0);
......@@ -852,7 +876,7 @@ public class StringUtils {
}
/**
* Trim a character from a substring. Equivalent of
* Trim a whitespace from a substring. Equivalent of
* {@code substring(beginIndex).trim()}.
*
* @param s the string
......@@ -864,7 +888,7 @@ public class StringUtils {
}
/**
* Trim a character from a substring. Equivalent of
* Trim a whitespace from a substring. Equivalent of
* {@code substring(beginIndex, endIndex).trim()}.
*
* @param s the string
......@@ -882,6 +906,27 @@ public class StringUtils {
return s.substring(beginIndex, endIndex);
}
/**
* Trim a whitespace from a substring and append it to a specified string
* builder. Equivalent of
* {@code builder.append(substring(beginIndex, endIndex).trim())}.
*
* @param builder string builder to append to
* @param s the string
* @param beginIndex start index of substring (inclusive)
* @param endIndex end index of substring (exclusive)
* @return the specified builder
*/
public static StringBuilder trimSubstring(StringBuilder builder, String s, int beginIndex, int endIndex) {
while (beginIndex < endIndex && s.charAt(beginIndex) <= ' ') {
beginIndex++;
}
while (beginIndex < endIndex && s.charAt(endIndex - 1) <= ' ') {
endIndex--;
}
return builder.append(s, beginIndex, endIndex);
}
/**
* Get the string from the cache if possible. If the string has not been
* found, it is added to the cache. If there is such a string in the cache,
......@@ -896,7 +941,7 @@ public class StringUtils {
}
if (s == null) {
return s;
} else if (s.length() == 0) {
} else if (s.isEmpty()) {
return "";
}
int hash = s.hashCode();
......@@ -1011,6 +1056,34 @@ public class StringUtils {
return new String(buff);
}
/**
* Convert a byte array to a hex encoded string and appends it to a specified string builder.
*
* @param builder string builder to append to
* @param value the byte array
* @return the hex encoded string
*/
public static StringBuilder convertBytesToHex(StringBuilder builder, byte[] value) {
return convertBytesToHex(builder, value, value.length);
}
/**
* Convert a byte array to a hex encoded string and appends it to a specified string builder.
*
* @param builder string builder to append to
* @param value the byte array
* @param len the number of bytes to encode
* @return the hex encoded string
*/
public static StringBuilder convertBytesToHex(StringBuilder builder, byte[] value, int len) {
char[] hex = HEX;
for (int i = 0; i < len; i++) {
int c = value[i] & 0xff;
builder.append(hex[c >>> 4]).append(hex[c & 0xf]);
}
return builder;
}
/**
* Check if this string is a decimal number.
*
......@@ -1078,7 +1151,7 @@ public class StringUtils {
* @return the escaped pattern
*/
public static String escapeMetaDataPattern(String pattern) {
if (pattern == null || pattern.length() == 0) {
if (pattern == null || pattern.isEmpty()) {
return pattern;
}
return replaceAll(pattern, "\\", "\\\\");
......
......@@ -362,13 +362,14 @@ public class ToChar {
}
int i = idx + 1;
boolean allZeroes = true;
for (; i < numberStr.length(); i++) {
int length = numberStr.length();
for (; i < length; i++) {
if (numberStr.charAt(i) != '0') {
allZeroes = false;
break;
}
}
final char[] zeroes = new char[allZeroes ? numberStr.length() - idx - 1: i - 1 - idx];
final char[] zeroes = new char[allZeroes ? length - idx - 1: i - 1 - idx];
Arrays.fill(zeroes, '0');
return String.valueOf(zeroes);
}
......@@ -688,7 +689,7 @@ public class ToChar {
StringBuilder output = new StringBuilder();
boolean fillMode = true;
for (int i = 0; i < format.length();) {
for (int i = 0, length = format.length(); i < length;) {
Capitalization cap;
......
......@@ -249,7 +249,7 @@ public class ToDateParser {
}
private boolean hasToParseData() {
return formatStr.length() > 0;
return !formatStr.isEmpty();
}
private void removeFirstChar() {
......
......@@ -651,7 +651,7 @@ class ToDateTokenizer {
* @return the list of tokens, or {@code null}
*/
static List<FormatTokenEnum> getTokensInQuestion(String formatStr) {
if (formatStr != null && formatStr.length() > 0) {
if (formatStr != null && !formatStr.isEmpty()) {
char key = Character.toUpperCase(formatStr.charAt(0));
if (key >= 'A' && key <= 'Y') {
List<FormatTokenEnum>[] tokens = TOKENS;
......
......@@ -222,12 +222,13 @@ public class CompareMode implements Comparator<Value> {
} else if (name.startsWith(CHARSET)) {
return new CharsetCollator(Charset.forName(name.substring(CHARSET.length())));
}
if (name.length() == 2) {
int length = name.length();
if (length == 2) {
Locale locale = new Locale(StringUtils.toLowerEnglish(name), "");
if (compareLocaleNames(locale, name)) {
result = Collator.getInstance(locale);
}
} else if (name.length() == 5) {
} else if (length == 5) {
// LL_CC (language_country)
int idx = name.indexOf('_');
if (idx >= 0) {
......
......@@ -49,12 +49,13 @@ public class CompareModeIcu4J extends CompareMode {
"com.ibm.icu.text.Collator");
Method getInstanceMethod = collatorClass.getMethod(
"getInstance", Locale.class);
if (name.length() == 2) {
int length = name.length();
if (length == 2) {
Locale locale = new Locale(StringUtils.toLowerEnglish(name), "");
if (compareLocaleNames(locale, name)) {
result = (Comparator<String>) getInstanceMethod.invoke(null, locale);
}
} else if (name.length() == 5) {
} else if (length == 5) {
// LL_CC (language_country)
int idx = name.indexOf('_');
if (idx >= 0) {
......
......@@ -52,7 +52,7 @@ public final class ExtTypeInfoEnum extends ExtTypeInfo {
}
result.append('\'');
String s = enumerators[i];
for (int j = 0; j < s.length(); j++) {
for (int j = 0, length = s.length(); j < length; j++) {
char c = s.charAt(j);
if (c == '\'') {
result.append('\'');
......
......@@ -275,7 +275,18 @@ public abstract class Value {
*
* @return the SQL expression
*/
public abstract String getSQL();
public String getSQL() {
return getSQL(new StringBuilder()).toString();
}
/**
* Appends the SQL expression for this value to the specified builder.
*
* @param builder
* string builder
* @return the specified string builder
*/
public abstract StringBuilder getSQL(StringBuilder builder);
/**
* Get the value type.
......@@ -1474,7 +1485,7 @@ public abstract class Value {
* @return the SQL expression
*/
public String getTraceSQL() {
return getSQL();
return getSQL(new StringBuilder()).toString();
}
@Override
......
......@@ -155,16 +155,19 @@ public class ValueArray extends Value {
}
@Override
public String getSQL() {
StatementBuilder buff = new StatementBuilder("(");
for (Value v : values) {
buff.appendExceptFirst(", ");
buff.append(v.getSQL());
public StringBuilder getSQL(StringBuilder builder) {
builder.append('(');
int length = values.length;
for (int i = 0; i < length; i++) {
if (i > 0) {
builder.append(", ");
}
values[i].getSQL(builder);
}
if (values.length == 1) {
buff.append(',');
if (length == 1) {
builder.append(',');
}
return buff.append(')').toString();
return builder.append(')');
}
@Override
......
......@@ -46,8 +46,8 @@ public class ValueBoolean extends Value {
}
@Override
public String getSQL() {
return getString();
public StringBuilder getSQL(StringBuilder builder) {
return builder.append(getString());
}
@Override
......
......@@ -88,8 +88,8 @@ public class ValueByte extends Value {
}
@Override
public String getSQL() {
return getString();
public StringBuilder getSQL(StringBuilder builder) {
return builder.append(value);
}
@Override
......
......@@ -79,8 +79,9 @@ public class ValueBytes extends Value {
}
@Override
public String getSQL() {
return "X'" + StringUtils.convertBytesToHex(getBytesNoCopy()) + "'";
public StringBuilder getSQL(StringBuilder builder) {
builder.append("X'");
return StringUtils.convertBytesToHex(builder, getBytesNoCopy()).append('\'');
}
@Override
......
......@@ -98,8 +98,10 @@ public class ValueDate extends Value {
}
@Override
public String getSQL() {
return "DATE '" + getString() + "'";
public StringBuilder getSQL(StringBuilder builder) {
builder.append("DATE '");
DateTimeUtils.appendDate(builder, dateValue);
return builder.append('\'');
}
@Override
......
......@@ -117,8 +117,8 @@ public class ValueDecimal extends Value {
}
@Override
public String getSQL() {
return getString();
public StringBuilder getSQL(StringBuilder builder) {
return builder.append(getString());
}
@Override
......
......@@ -92,15 +92,17 @@ public class ValueDouble extends Value {
}
@Override
public String getSQL() {
public StringBuilder getSQL(StringBuilder builder) {
if (value == Double.POSITIVE_INFINITY) {
return "POWER(0, -1)";
builder.append("POWER(0, -1)");
} else if (value == Double.NEGATIVE_INFINITY) {
return "(-POWER(0, -1))";
builder.append("(-POWER(0, -1))");
} else if (Double.isNaN(value)) {
return "SQRT(-1)";
builder.append("SQRT(-1)");
} else {
builder.append(value);
}
return getString();
return builder;
}
@Override
......
......@@ -94,8 +94,8 @@ public class ValueEnumBase extends Value {
}
@Override
public String getSQL() {
return StringUtils.quoteStringSQL(label);
public StringBuilder getSQL(StringBuilder builder) {
return StringUtils.quoteStringSQL(builder, label);
}
@Override
......
......@@ -92,16 +92,17 @@ public class ValueFloat extends Value {
}
@Override
public String getSQL() {
public StringBuilder getSQL(StringBuilder builder) {
if (value == Float.POSITIVE_INFINITY) {
return "POWER(0, -1)";
builder.append("POWER(0, -1)");
} else if (value == Float.NEGATIVE_INFINITY) {
return "(-POWER(0, -1))";
builder.append("(-POWER(0, -1))");
} else if (Float.isNaN(value)) {
// NaN
return "SQRT(-1)";
builder.append("SQRT(-1)");
} else {
builder.append(value);
}
return getString();
return builder;
}
@Override
......
......@@ -268,9 +268,10 @@ public class ValueGeometry extends Value {
}
@Override
public String getSQL() {
public StringBuilder getSQL(StringBuilder builder) {
// Using bytes is faster than converting to EWKT.
return "X'" + StringUtils.convertBytesToHex(getBytesNoCopy()) + "'::Geometry";
builder.append("X'");
return StringUtils.convertBytesToHex(builder, getBytesNoCopy()).append("'::Geometry");
}
@Override
......
......@@ -121,8 +121,8 @@ public class ValueInt extends Value {
}
@Override
public String getSQL() {
return getString();
public StringBuilder getSQL(StringBuilder builder) {
return builder.append(value);
}
@Override
......
......@@ -138,8 +138,8 @@ public class ValueInterval extends Value {
}
@Override
public String getSQL() {
return getString();
public StringBuilder getSQL(StringBuilder builder) {
return IntervalUtils.appendInterval(builder, getQualifier(), negative, leading, remaining);
}
@Override
......@@ -211,7 +211,8 @@ public class ValueInterval extends Value {
@Override
public String getString() {
return IntervalUtils.intervalToString(getQualifier(), negative, leading, remaining);
return IntervalUtils.appendInterval(new StringBuilder(), getQualifier(), negative, leading, remaining)
.toString();
}
@Override
......
......@@ -275,7 +275,7 @@ public class ValueLob extends Value {
private static int getNewObjectId(DataHandler h) {
String path = h.getDatabasePath();
if ((path != null) && (path.length() == 0)) {
if (path != null && path.isEmpty()) {
path = new File(Utils.getProperty("java.io.tmpdir", "."),
SysProperties.PREFIX_TEMP_FILE).getAbsolutePath();
}
......@@ -570,15 +570,14 @@ public class ValueLob extends Value {
}
@Override
public String getSQL() {
String s;
public StringBuilder getSQL(StringBuilder builder) {
if (valueType == Value.CLOB) {
s = getString();
return StringUtils.quoteStringSQL(s);
StringUtils.quoteStringSQL(builder, getString());
} else {
builder.append("X'");
StringUtils.convertBytesToHex(builder, getBytes()).append('\'');
}
byte[] buff = getBytes();
s = StringUtils.convertBytesToHex(buff);
return "X'" + s + "'";
return builder;
}
@Override
......
......@@ -176,7 +176,7 @@ public class ValueLobDb extends Value {
private static String createTempLobFileName(DataHandler handler)
throws IOException {
String path = handler.getDatabasePath();
if (path.length() == 0) {
if (path.isEmpty()) {
path = SysProperties.PREFIX_TEMP_FILE;
}
return FileUtils.createTempFile(path, Constants.SUFFIX_TEMP_FILE, true, true);
......@@ -461,15 +461,14 @@ public class ValueLobDb extends Value {
}
@Override
public String getSQL() {
String s;
public StringBuilder getSQL(StringBuilder builder) {
if (valueType == Value.CLOB) {
s = getString();
return StringUtils.quoteStringSQL(s);
StringUtils.quoteStringSQL(builder, getString());
} else {
builder.append("X'");
StringUtils.convertBytesToHex(builder, getBytes()).append('\'');
}
byte[] buff = getBytes();
s = StringUtils.convertBytesToHex(buff);
return "X'" + s + "'";
return builder;
}
@Override
......
......@@ -146,8 +146,8 @@ public class ValueLong extends Value {
}
@Override
public String getSQL() {
return getString();
public StringBuilder getSQL(StringBuilder builder) {
return builder.append(value);
}
@Override
......
......@@ -49,8 +49,8 @@ public class ValueNull extends Value {
}
@Override
public String getSQL() {
return "NULL";
public StringBuilder getSQL(StringBuilder builder) {
return builder.append("NULL");
}
@Override
......
......@@ -166,8 +166,8 @@ public class ValueResultSet extends Value {
}
@Override
public String getSQL() {
return "";
public StringBuilder getSQL(StringBuilder builder) {
return builder;
}
@Override
......
......@@ -88,8 +88,8 @@ public class ValueShort extends Value {
}
@Override
public String getSQL() {
return getString();
public StringBuilder getSQL(StringBuilder builder) {
return builder.append(value);
}
@Override
......
......@@ -34,8 +34,8 @@ public class ValueString extends Value {
}
@Override
public String getSQL() {
return StringUtils.quoteStringSQL(value);
public StringBuilder getSQL(StringBuilder builder) {
return StringUtils.quoteStringSQL(builder, value);
}
@Override
......
......@@ -47,13 +47,13 @@ public class ValueStringFixed extends ValueString {
}
private static String rightPadWithSpaces(String s, int length) {
int pad = length - s.length();
if (pad <= 0) {
int used = s.length();
if (length <= used) {
return s;
}
char[] res = new char[length];
s.getChars(0, s.length(), res, 0);
Arrays.fill(res, s.length(), length, ' ');
s.getChars(0, used, res, 0);
Arrays.fill(res, used, length, ' ');
return new String(res);
}
......@@ -109,11 +109,12 @@ public class ValueStringFixed extends ValueString {
// Default behaviour of H2
s = trimRight(s);
}
if (s.length() == 0) {
int length = s.length();
if (length == 0) {
return EMPTY;
}
ValueStringFixed obj = new ValueStringFixed(StringUtils.cache(s));
if (s.length() > SysProperties.OBJECT_CACHE_MAX_PER_ELEMENT_SIZE) {
if (length > SysProperties.OBJECT_CACHE_MAX_PER_ELEMENT_SIZE) {
return obj;
}
return (ValueStringFixed) Value.cache(obj);
......
......@@ -47,8 +47,9 @@ public class ValueStringIgnoreCase extends ValueString {
}
@Override
public String getSQL() {
return "CAST(" + StringUtils.quoteStringSQL(value) + " AS VARCHAR_IGNORECASE)";
public StringBuilder getSQL(StringBuilder builder) {
builder.append("CAST(");
return StringUtils.quoteStringSQL(builder, value).append(" AS VARCHAR_IGNORECASE)");
}
/**
......@@ -59,11 +60,12 @@ public class ValueStringIgnoreCase extends ValueString {
* @return the value
*/
public static ValueStringIgnoreCase get(String s) {
if (s.length() == 0) {
int length = s.length();
if (length == 0) {
return EMPTY;
}
ValueStringIgnoreCase obj = new ValueStringIgnoreCase(StringUtils.cache(s));
if (s.length() > SysProperties.OBJECT_CACHE_MAX_PER_ELEMENT_SIZE) {
if (length > SysProperties.OBJECT_CACHE_MAX_PER_ELEMENT_SIZE) {
return obj;
}
ValueStringIgnoreCase cache = (ValueStringIgnoreCase) Value.cache(obj);
......
......@@ -138,8 +138,10 @@ public class ValueTime extends Value {
}
@Override
public String getSQL() {
return "TIME '" + getString() + "'";
public StringBuilder getSQL(StringBuilder builder) {
builder.append("TIME '");
DateTimeUtils.appendTime(builder, nanos);
return builder.append('\'');
}
@Override
......
......@@ -188,8 +188,12 @@ public class ValueTimestamp extends Value {
}
@Override
public String getSQL() {
return "TIMESTAMP '" + getString() + "'";
public StringBuilder getSQL(StringBuilder builder) {
builder.append("TIMESTAMP '");
DateTimeUtils.appendDate(builder, dateValue);
builder.append(' ');
DateTimeUtils.appendTime(builder, timeNanos);
return builder.append('\'');
}
@Override
......
......@@ -175,12 +175,16 @@ public class ValueTimestampTimeZone extends Value {
@Override
public String getString() {
return DateTimeUtils.timestampTimeZoneToString(dateValue, timeNanos, timeZoneOffsetMins);
StringBuilder builder = new StringBuilder(ValueTimestampTimeZone.MAXIMUM_PRECISION);
DateTimeUtils.appendTimestampTimeZone(builder, dateValue, timeNanos, timeZoneOffsetMins);
return builder.toString();
}
@Override
public String getSQL() {
return "TIMESTAMP WITH TIME ZONE '" + getString() + "'";
public StringBuilder getSQL(StringBuilder builder) {
builder.append("TIMESTAMP WITH TIME ZONE '");
DateTimeUtils.appendTimestampTimeZone(builder, dateValue, timeNanos, timeZoneOffsetMins);
return builder.append('\'');
}
@Override
......
......@@ -126,8 +126,9 @@ public class ValueUuid extends Value {
}
@Override
public String getSQL() {
return StringUtils.quoteStringSQL(getString());
public StringBuilder getSQL(StringBuilder builder) {
builder.append('\'');
return addString(builder).append('\'');
}
@Override
......@@ -149,17 +150,20 @@ public class ValueUuid extends Value {
@Override
public String getString() {
StringBuilder buff = new StringBuilder(36);
appendHex(buff, high >> 32, 4);
buff.append('-');
appendHex(buff, high >> 16, 2);
buff.append('-');
appendHex(buff, high, 2);
buff.append('-');
appendHex(buff, low >> 48, 2);
buff.append('-');
appendHex(buff, low, 6);
return buff.toString();
return addString(new StringBuilder(36)).toString();
}
private StringBuilder addString(StringBuilder builder) {
appendHex(builder, high >> 32, 4);
builder.append('-');
appendHex(builder, high >> 16, 2);
builder.append('-');
appendHex(builder, high, 2);
builder.append('-');
appendHex(builder, low >> 48, 2);
builder.append('-');
appendHex(builder, low, 6);
return builder;
}
@Override
......
......@@ -337,8 +337,8 @@ public class TestCustomDataTypesHandler extends TestDb {
}
@Override
public String getSQL() {
return val.toString();
public StringBuilder getSQL(StringBuilder builder) {
return builder.append(val.toString());
}
@Override
......
......@@ -10,4 +10,10 @@ select * from test where id = (1, 2);
> exception COMPARING_ARRAY_TO_SCALAR
drop table test;
> ok
\ No newline at end of file
> ok
SELECT 1 + 2 NOT;
> exception SYNTAX_ERROR_2
SELECT 1 NOT > 2;
> exception SYNTAX_ERROR_2
......@@ -281,14 +281,22 @@ public class TestStringUtils extends TestBase {
}
private void testTrimSubstring() {
assertEquals("", StringUtils.trimSubstring("", 0, 0));
assertEquals("", StringUtils.trimSubstring(" ", 0, 0));
assertEquals("", StringUtils.trimSubstring(" ", 4, 4));
assertEquals("select", StringUtils.trimSubstring(" select from", 1, 7));
assertEquals("a b", StringUtils.trimSubstring(" a b ", 1, 4));
testTrimSubstringImpl("", "", 0, 0);
testTrimSubstringImpl("", " ", 0, 0);
testTrimSubstringImpl("", " ", 4, 4);
testTrimSubstringImpl("select", " select from", 1, 7);
testTrimSubstringImpl("a b", " a b ", 1, 4);
testTrimSubstringImpl("a b", " a b ", 1, 5);
testTrimSubstringImpl("b", " a b ", 2, 5);
new AssertThrows(StringIndexOutOfBoundsException.class) { @Override
public void test() { StringUtils.trimSubstring(" with (", 1, 8); }
};
}
private void testTrimSubstringImpl(String expected, String string, int startIndex, int endIndex) {
assertEquals(expected, StringUtils.trimSubstring(string, startIndex, endIndex));
assertEquals(expected, StringUtils
.trimSubstring(new StringBuilder(endIndex - startIndex), string, startIndex, endIndex).toString());
}
}
......@@ -801,4 +801,4 @@ partitioned tri partitions
discard enhancements nolock surefire logarithm
qualification opportunity jumping exploited unacceptable vrs duplicated
queryparser tokenized freeze
queryparser tokenized freeze factorings recompilation unenclosed
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论